Reindex API Version Conflicts: Reconciling Old-Index Writes Before Alias Cutover
0 reputation · 09 Oct 2025, 02:50 UTC
0 reputation · 09 Oct 2025, 02:50 UTC
Planning a zero-downtime index migration for a small Elasticsearch application using the Reindex API and an atomic alias cutover. The Reindex API aborts when source documents are updated during the job, and the conflicts parameter changes that behavior only by skipping conflicting documents, which silently drops those updates. An aliases API request can atomically remove the old index and add the new one, but writes that reach the old index during the reindex window are not automatically reconciled afterward.
The unresolved decision is how to handle that write window before the alias swap. Options include a brief write freeze, application-level dual writes, or a final delta reindex, each carrying different consistency and complexity tradeoffs for a small deployment. Because the Reindex API copies only documents and not settings or mappings, the destination index must be created up front with the intended configuration, and clients must address the alias rather than a concrete index name. Version-sensitive behavior around mapping types and remote reindex settings means the exact parameters must match the deployed Elasticsearch version.
For a small cluster, throttling the reindex with requests_per_second and running it asynchronously with wait_for_completion=false are standard resource controls, but they do not resolve the write-loss question. Which reconciliation strategy best preserves data integrity without introducing downtime for a small application? What verification steps confirm that no updates were lost before the alias is switched, and how should the reindex task be monitored to ensure the write window is fully accounted for?
35275 reputation · 09 Oct 2025, 09:57 UTC
For a small Elasticsearch application, the safest reconciliation strategy is a final-delta reindex with a brief write pause. Run the bulk copy asynchronously, then briefly pause or queue incoming writes, execute a second delta reindex to capture the write window, verify that no conflicts remain, and finally perform the atomic alias swap. Continuous dual writes add ordering and partial-failure risk that outweighs their benefit at this scale.
Setting conflicts=proceed allows the Reindex API to continue past version conflicts, but it does not copy the conflicting source updates. A nonzero version_conflicts count in the task response means those writes were skipped, not reconciled. Treat it as pending work, not success.
wait_for_completion=false and a conservative requests_per_second to protect the small cluster. Use conflicts=proceed so the job does not abort on concurrent updates.updated_at field. A full delta is safer for small datasets._aliases request that removes the old index and adds the new one with is_write_index: true.Refresh the destination index, then compare GET /<old>/_count and GET /<new>/_count. For a small dataset, scroll both sides and compare _id, _routing, and _source or stable hashes rather than relying on counts alone. The delta is complete only when counts and content match and the task response reports version_conflicts: 0 with no failures. Do not rely on _version equality unless your reindex path preserves versions.
Confirm the destination configuration with GET /<new>/_mapping and GET /<new>/_settings, and verify alias state with GET /_alias/<alias> before and after the swap: exactly one index, with is_write_index on the new index after cutover.
Save the task ID returned by the asynchronous reindex and poll GET /_tasks/<task_id>?detailed=true until completed is true. Check response.total, created, updated, version_conflicts, failures, and the batch count. Never cut over while the task is running or after failures. If version_conflicts is nonzero after the write pause, run another delta.
Can your application tolerate a short write pause or queue during the final delta? If writes must never fail, the recommendation changes to an external queue or idempotent ordered dual-write design, which is more complex but removes the unavailability window.
Version note: Mapping types were removed in Elasticsearch 8, and remote-reindex allow/whitelist setting names differ across 7.x and 8.x. Confirm exact parameter names against your deployed version before relying on them.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.