From 313faa02fedd7085c60d2b1b5e0b3c4a466da551 Mon Sep 17 00:00:00 2001 From: "CanbiZ (MickLesk)" <47820557+MickLesk@users.noreply.github.com> Date: Fri, 30 Jan 2026 10:29:08 +0100 Subject: [PATCH] fix(meilisearch): fix dump creation and improve migration handling Bug fixes: - dumpUid is only available AFTER the dump task completes, not in the initial POST /dumps response. Fixed the extraction logic to wait for task completion first, then extract dumpUid from the task result. - Removed non-existent API endpoint /dumps/{uid}/import - Meilisearch only supports dump import via CLI flag --import-dump Improvements: - If dump creation fails, backup the data directory before proceeding instead of just overwriting (allows manual recovery) - Better error messages with actual API response content - Proper health check loop during import with process monitoring - Clear user guidance about what to do after failed migration Fixes #11349 --- misc/tools.func | 146 +++++++++++++++++++++++++++++------------------- 1 file changed, 89 insertions(+), 57 deletions(-) diff --git a/misc/tools.func b/misc/tools.func index 6eb05df7a..05fe7bb01 100644 --- a/misc/tools.func +++ b/misc/tools.func @@ -5218,40 +5218,69 @@ function setup_meilisearch() { -H "Authorization: Bearer ${MEILI_MASTER_KEY}" \ -H "Content-Type: application/json" 2>/dev/null) || true - DUMP_UID=$(echo "$DUMP_RESPONSE" | grep -oP '"dumpUid":\s*"\K[^"]+' || true) + # The initial response only contains taskUid, not dumpUid + # dumpUid is only available after the task completes + local TASK_UID + TASK_UID=$(echo "$DUMP_RESPONSE" | grep -oP '"taskUid":\s*\K[0-9]+' || true) - if [[ -n "$DUMP_UID" ]]; then - # Wait for dump to complete (check task status) - local TASK_UID - TASK_UID=$(echo "$DUMP_RESPONSE" | grep -oP '"taskUid":\s*\K[0-9]+' || true) - - if [[ -n "$TASK_UID" ]]; then - msg_info "Waiting for dump task ${TASK_UID} to complete..." - local MAX_WAIT=120 - local WAITED=0 - while [[ $WAITED -lt $MAX_WAIT ]]; do - local TASK_STATUS - TASK_STATUS=$(curl -s "http://${MEILI_HOST}:${MEILI_PORT}/tasks/${TASK_UID}" \ - -H "Authorization: Bearer ${MEILI_MASTER_KEY}" 2>/dev/null | grep -oP '"status":\s*"\K[^"]+' || true) - if [[ "$TASK_STATUS" == "succeeded" ]]; then + if [[ -n "$TASK_UID" ]]; then + msg_info "Waiting for dump task ${TASK_UID} to complete..." + local MAX_WAIT=120 + local WAITED=0 + local TASK_RESULT="" + + while [[ $WAITED -lt $MAX_WAIT ]]; do + TASK_RESULT=$(curl -s "http://${MEILI_HOST}:${MEILI_PORT}/tasks/${TASK_UID}" \ + -H "Authorization: Bearer ${MEILI_MASTER_KEY}" 2>/dev/null) || true + + local TASK_STATUS + TASK_STATUS=$(echo "$TASK_RESULT" | grep -oP '"status":\s*"\K[^"]+' || true) + + if [[ "$TASK_STATUS" == "succeeded" ]]; then + # Extract dumpUid from the completed task details + DUMP_UID=$(echo "$TASK_RESULT" | grep -oP '"dumpUid":\s*"\K[^"]+' || true) + if [[ -n "$DUMP_UID" ]]; then msg_ok "MeiliSearch dump created successfully: ${DUMP_UID}" - break - elif [[ "$TASK_STATUS" == "failed" ]]; then - msg_warn "MeiliSearch dump failed, proceeding without migration" - DUMP_UID="" - break + else + msg_warn "Dump task succeeded but could not extract dumpUid" fi - sleep 2 - WAITED=$((WAITED + 2)) - done - - if [[ $WAITED -ge $MAX_WAIT ]]; then - msg_warn "MeiliSearch dump timed out, proceeding without migration" - DUMP_UID="" + break + elif [[ "$TASK_STATUS" == "failed" ]]; then + local ERROR_MSG + ERROR_MSG=$(echo "$TASK_RESULT" | grep -oP '"message":\s*"\K[^"]+' || echo "Unknown error") + msg_warn "MeiliSearch dump failed: ${ERROR_MSG}" + break fi + sleep 2 + WAITED=$((WAITED + 2)) + done + + if [[ $WAITED -ge $MAX_WAIT ]]; then + msg_warn "MeiliSearch dump timed out after ${MAX_WAIT}s" fi else - msg_warn "Could not create MeiliSearch dump, proceeding with direct upgrade" + msg_warn "Could not trigger MeiliSearch dump (no taskUid in response)" + msg_info "Response was: ${DUMP_RESPONSE:-empty}" + fi + fi + + # If migration is needed but dump failed, we have options: + # 1. Abort the update (safest, but annoying) + # 2. Backup data directory and proceed (allows manual recovery) + # 3. Just proceed and hope for the best (dangerous) + # We choose option 2: backup and proceed with warning + if [[ "$NEEDS_MIGRATION" == "true" ]] && [[ -z "$DUMP_UID" ]]; then + local MEILI_DB_PATH + MEILI_DB_PATH=$(grep -E "^db_path\s*=" /etc/meilisearch.toml 2>/dev/null | sed 's/.*=\s*"\(.*\)"/\1/' | tr -d ' ') + MEILI_DB_PATH="${MEILI_DB_PATH:-/var/lib/meilisearch/data}" + + if [[ -d "$MEILI_DB_PATH" ]] && [[ -n "$(ls -A "$MEILI_DB_PATH" 2>/dev/null)" ]]; then + local BACKUP_PATH="${MEILI_DB_PATH}.backup.$(date +%Y%m%d%H%M%S)" + msg_warn "Backing up MeiliSearch data to ${BACKUP_PATH}" + mv "$MEILI_DB_PATH" "$BACKUP_PATH" + mkdir -p "$MEILI_DB_PATH" + msg_info "Data backed up. After update, you may need to reindex your data." + msg_info "Old data is preserved at: ${BACKUP_PATH}" fi fi @@ -5268,45 +5297,48 @@ function setup_meilisearch() { msg_info "Removing old MeiliSearch database for migration" rm -rf "${MEILI_DB_PATH:?}"/* - # Start with dump import - msg_info "Starting MeiliSearch with dump import" - systemctl start meilisearch - - # Import dump via API - local IMPORT_RESPONSE - IMPORT_RESPONSE=$(curl -s -X POST "http://${MEILI_HOST}:${MEILI_PORT}/dumps/${DUMP_UID}/import" \ - -H "Authorization: Bearer ${MEILI_MASTER_KEY}" 2>/dev/null) || true - - # Wait for import to complete - local IMPORT_TASK_UID - IMPORT_TASK_UID=$(echo "$IMPORT_RESPONSE" | grep -oP '"taskUid":\s*\K[0-9]+' || true) - - if [[ -n "$IMPORT_TASK_UID" ]]; then - msg_info "Waiting for dump import task ${IMPORT_TASK_UID} to complete..." + # Import dump using CLI flag (this is the supported method) + local DUMP_FILE="${MEILI_DUMP_DIR}/${DUMP_UID}.dump" + if [[ -f "$DUMP_FILE" ]]; then + msg_info "Importing dump: ${DUMP_FILE}" + + # Start meilisearch with --import-dump flag + # This is a one-time import that happens during startup + /usr/bin/meilisearch --config-file-path /etc/meilisearch.toml --import-dump "$DUMP_FILE" & + local MEILI_PID=$! + + # Wait for meilisearch to become healthy (import happens during startup) + msg_info "Waiting for MeiliSearch to import and start..." local MAX_WAIT=300 local WAITED=0 while [[ $WAITED -lt $MAX_WAIT ]]; do - local TASK_STATUS - TASK_STATUS=$(curl -s "http://${MEILI_HOST}:${MEILI_PORT}/tasks/${IMPORT_TASK_UID}" \ - -H "Authorization: Bearer ${MEILI_MASTER_KEY}" 2>/dev/null | grep -oP '"status":\s*"\K[^"]+' || true) - if [[ "$TASK_STATUS" == "succeeded" ]]; then - msg_ok "MeiliSearch dump imported successfully" + if curl -sf "http://${MEILI_HOST}:${MEILI_PORT}/health" &>/dev/null; then + msg_ok "MeiliSearch is healthy after import" break - elif [[ "$TASK_STATUS" == "failed" ]]; then - msg_warn "MeiliSearch dump import failed - manual intervention may be required" + fi + # Check if process is still running + if ! kill -0 $MEILI_PID 2>/dev/null; then + msg_warn "MeiliSearch process exited during import" break fi sleep 3 WAITED=$((WAITED + 3)) done - else - # Fallback: Start with --import-dump flag (for older API versions) - systemctl stop meilisearch - msg_info "Attempting dump import via command line" - /usr/bin/meilisearch --config-file-path /etc/meilisearch.toml --import-dump "${MEILI_DUMP_DIR}/${DUMP_UID}.dump" &>/dev/null & - local MEILI_PID=$! - sleep 10 + + # Stop the manual process kill $MEILI_PID 2>/dev/null || true + sleep 2 + + # Start via systemd for proper management + systemctl start meilisearch + + if systemctl is-active --quiet meilisearch; then + msg_ok "MeiliSearch migrated successfully" + else + msg_warn "MeiliSearch failed to start after migration - check logs with: journalctl -u meilisearch" + fi + else + msg_warn "Dump file not found: ${DUMP_FILE}" systemctl start meilisearch fi else