CollectionInfo icon
If icon
SlackIncomingWebhook icon
Fail icon
Query icon
Request icon
OutputValues icon
Switch icon
Log icon
Pause icon
Sleep icon

Zero-Downtime Qdrant Collection Alias Cutover and Pre-Flight Indexing Gate

Orchestrate zero-downtime Qdrant alias cutovers with Kestra. Verify collection status and indexing, run a canary search, then switch the alias atomically.

Categories
AIInfrastructure

When you rebuild a Qdrant collection with a new embedding model or new HNSW settings, applications should only be pointed at it once it is ready. Switching an alias to a collection that is still indexing makes searches slow, and a two-step delete-then-create leaves a moment where the alias does not exist.

This blueprint checks the new collection over gRPC, runs a canary similarity search against it, reads the current alias mapping over REST, waits for an operator to approve, and then sends one atomic alias update. It reads the aliases again afterwards and fails if the alias does not point at the new collection. It defaults to a dry run, so nothing changes until you turn dry_run off.

How it works

  1. probe_candidate_collection (io.kestra.plugin.qdrant.CollectionInfo) reads the status, the point count and the indexed vector count of candidate_collection over gRPC.
  2. validate_candidate_readiness (io.kestra.plugin.core.flow.If) posts to Slack and stops with io.kestra.plugin.core.execution.Fail when the status is not Green, the collection has no points, or the unindexed vectors exceed max_indexing_lag.
  3. canary_vector_search (io.kestra.plugin.qdrant.Query) runs a 1-NN search seeded by canary_point_id, and validate_canary_recall fails the flow when it returns nothing.
  4. inspect_current_aliases (io.kestra.plugin.core.http.Request) calls GET /aliases, and resolve_alias_state (io.kestra.plugin.core.output.OutputValues) uses jq to find where alias_name points now and whether it already points at the candidate.
  5. route_cutover_decision (io.kestra.plugin.core.flow.Switch) ends the flow cleanly with ALREADY_ACTIVE, or continues with CUTOVER_REQUIRED.
  6. When require_manual_approval is on and dry_run is off, await_operator_approval (io.kestra.plugin.core.flow.Pause) waits up to four hours for an operator to resume with the approval box ticked. Resuming without ticking it cancels the cutover.
  7. With dry_run off, apply_atomic_alias_mutation sends one POST /collections/aliases request with a delete_alias (only when the alias exists) and a create_alias action. Qdrant applies the actions of a request together, so the alias is never missing.
  8. After settle_consensus (io.kestra.plugin.core.flow.Sleep), reverify_active_alias reads the aliases again. A mismatch posts a critical Slack alert and fails the execution. With dry_run on, log_dry_run_summary logs the planned change.

What you get

  • No moment where the alias is unmapped, because the delete and create happen in one request.
  • A check that the new collection is Green, non-empty and not lagging on indexing before traffic moves.
  • A canary search that proves the new collection can answer queries.
  • A no-op when the alias already points at the candidate.
  • A safe default: dry run on, approval required, and a failed execution if the result cannot be verified.

Who it's for

  • MLOps and Platform Engineers: Teams that rebuild embeddings and indexes behind live RAG services.
  • Search SREs and Database Administrators: Teams that migrate or retune vector collections.
  • AI Application Teams: Teams that need semantic search to stay available during an index change.

Why orchestrate this with Kestra

  • One flow for gRPC and REST: The collection checks use the Qdrant plugin and the alias change uses the REST API, in one execution history.
  • Built-in approval: A Pause task lets an operator review the numbers in the Kestra UI and approve there.
  • Visible failure paths: Every rejection posts to Slack and fails the execution, and the flow-level errors handler covers unexpected task failures.
  • One cutover at a time: A flow concurrency limit of 1 with QUEUE keeps two cutovers from running together.

Prerequisites

  • A Qdrant instance reachable over HTTP (6333) and gRPC (6334), with a populated candidate collection.
  • A point ID that exists in the candidate collection, for the canary search.
  • A Slack Incoming Webhook URL.

Secrets

  • QDRANT_API_KEY: API key for Qdrant. The flow always reads this secret, so create it even if your instance has no authentication (an empty value works).
  • SLACK_WEBHOOK: Incoming webhook URL for cutover, approval and failure messages.

Quick start

  1. Add QDRANT_API_KEY and SLACK_WEBHOOK to your Kestra namespace secrets.
  2. Import this blueprint into your Kestra instance.
  3. Run it with candidate_collection, alias_name and canary_point_id set and dry_run left on, and read the logs.
  4. Run it again with dry_run off, then resume the paused execution with the approval box ticked.

How to extend

  • Snapshot the old collection: Call the Qdrant snapshot API for the previous target before you decommission it.
  • Roll back automatically: Add a webhook-triggered flow that moves the alias back to the previous target when error rates rise.
  • Schedule it: Add a Schedule trigger with an inputs: block that names your collection and alias.

Links

See How

New to Kestra?

Use blueprints to kickstart your first workflows.