Decouple on-write search reindex from request latency (background task) #23

Open
opened 2026-06-02 21:31:08 +00:00 by logaritmisk · 0 comments
Owner

Context

On-write reindex (#17, merged d15afda) runs inline: the api::reindex helper .awaits SearchClient::sync_object, which itself .awaits Meilisearch's wait_for_completion. So every admin catalogue write (create/update/delete/fields/visibility) blocks on Meilisearch finishing the index task before the handler returns. A slow or stalled Meili adds latency to writes (worst case, blocks until the SDK's completion poll resolves/times out). Failures are already logged-not-propagated, so correctness is fine — this is purely about write latency coupling to search health.

What to do

Decouple indexing from the request path, e.g. one of:

  • tokio::spawn the sync_object call (fire-and-forget) after commit — AppState/SearchClient/the db pool are all cheap to clone; keep the tracing::error! on failure.
  • or a small bounded queue / channel drained by a background task, so bursts don't spawn unbounded tasks.

Either way: keep the best-effort semantics (a committed write must never fail or block on Meili), and keep reindex_all as the recovery path. Note that backgrounding makes the api/tests/reindex.rs assertions racy — they currently rely on the inline wait_for_completion; they'd need a poll/retry helper or to test sync_object at the unit level instead.

References

  • crates/api/src/lib.rsreindex helper (inline .await)
  • crates/search/src/lib.rssync_object / index_object (wait_for_completion)
  • Surfaced in the #17 code review.
## Context On-write reindex (#17, merged `d15afda`) runs **inline**: the `api::reindex` helper `.await`s `SearchClient::sync_object`, which itself `.await`s Meilisearch's `wait_for_completion`. So every admin catalogue write (create/update/delete/fields/visibility) blocks on Meilisearch finishing the index task before the handler returns. A slow or stalled Meili adds latency to writes (worst case, blocks until the SDK's completion poll resolves/times out). Failures are already logged-not-propagated, so correctness is fine — this is purely about write latency coupling to search health. ## What to do Decouple indexing from the request path, e.g. one of: - `tokio::spawn` the `sync_object` call (fire-and-forget) after commit — `AppState`/`SearchClient`/the db pool are all cheap to clone; keep the `tracing::error!` on failure. - or a small bounded queue / channel drained by a background task, so bursts don't spawn unbounded tasks. Either way: keep the best-effort semantics (a committed write must never fail or block on Meili), and keep `reindex_all` as the recovery path. Note that backgrounding makes the `api/tests/reindex.rs` assertions racy — they currently rely on the inline `wait_for_completion`; they'd need a poll/retry helper or to test `sync_object` at the unit level instead. ## References - `crates/api/src/lib.rs` — `reindex` helper (inline `.await`) - `crates/search/src/lib.rs` — `sync_object` / `index_object` (`wait_for_completion`) - Surfaced in the #17 code review.
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: logaritmisk/biggus-dickus#23