Skip to content

docs: loaded documents may not be immediately searchable on Redis 8.8+ under concurrent load #662

Description

@nkanu17

Summary

On Redis 8.8 and later, the RediSearch worker pool defaults to a multithreaded background executor (search-workers defaults to the core count rather than 0). Under concurrent write and query load, FT.SEARCH briefly loses read-your-writes consistency: documents that have already been written to the keyspace are not yet visible to a query issued immediately afterwards.

This is server behavior rather than a redisvl defect, but it affects a common redisvl usage pattern, so it is worth documenting.

index.load(records)
results = index.query(query)   # may not include everything just loaded

Evidence

Harness: 8 threads, each creating an index, loading 3 documents, and immediately querying with FilterQuery(filter_expression="*", sort_by="title") expecting all 3. 60 iterations per thread, 480 total, against redis:latest (Redis 8.10.0).

configuration shortfalls documents seen at first query
search-workers 14 (image default), 1 CPU 17/480 0, 1, or 2 instead of 3
search-workers 14 (image default), unconstrained CPU 17/480 0, 1, or 2 instead of 3
search-workers 0 0/480 always 3

A single-threaded probe against an idle server shows no shortfall, so concurrency is required to surface this.

The writes themselves are never lost. Across 30 shortfall events, all 3 hashes were already present in the keyspace at the moment the query returned fewer, and the index caught up every time:

docs present in keyspace during every shortfall: True (3 of 3 expected)
index caught up in all cases: 30/30
convergence delay ms: min=0.8  median=1.6  max=2.6

So the window is short, roughly 1 to 3 ms in these runs, but it is real and it scales with load.

Why this matters for redisvl users

Any code that writes and then immediately reads through the index can observe incomplete results:

  • load() followed directly by query()
  • ingestion pipelines that write and verify in the same request
  • SemanticCache and MessageHistory style flows that store an entry and then immediately search for it

The failure mode is quiet: a query returns fewer rows rather than raising, so it can look like a relevance or filtering problem.

This is also the confirmed cause of a family of nondeterministic CI failures in this repository on the redis:latest matrix jobs (see #658 and #659), where tests loading a handful of documents and querying immediately saw 0, 1, or 2 of them.

Suggestions

  1. Document the behavior for users on Redis 8.8+, ideally near load() in the user guide and API docs, including that it applies only under concurrent load and that the window is short.
  2. Note the server-side option for workloads that need synchronous indexing: starting Redis with --search-workers 0 restores foreground indexing and eliminates the window, at the cost of the multithreaded indexing benefits.
  3. Consider whether any first-class support is warranted, for example an opt-in helper that waits for an expected document count or polls until an index reflects a just-completed load. This should be weighed carefully: polling has obvious downsides, and it may be better to simply document the behavior and leave the decision to callers.

Reproduction scripts used for the numbers above can be attached if useful.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions