Async indexing
IndexWriter provides asynchronous ingestion for applications that must avoid blocking while waiting for the writer queue and backpressure. Indexing semantics, validation, flushes, merges, and commits are shared with the synchronous path.
One document
await writer.AddDocumentAsync(document, cancellationToken);
The document is validated, written to the writer's bounded asynchronous command channel, and completed after the command has passed through the normal documents-writer-per-thread pipeline. It is not implemented as one Task.Run per document.
Use synchronous AddDocument in a dedicated indexing worker when the caller is already allowed to block. Use the async form in request, stream, or channel consumers that need cooperative backpressure.
A known batch
IReadOnlyList<LeanDocument> batch = BuildBatch();
await writer.AddDocumentsAsync(batch, cancellationToken);
The batch is validated before it is queued. If backpressure is enabled and the batch exceeds MaxQueuedDocs, LeanCorpus submits its documents individually instead of attempting to reserve an impossible batch.
Stream documents
await writer.AddDocumentsAsync(
GetDocumentsAsync(cancellationToken),
batchSize: 256,
cancellationToken);
The effective batch size is the smaller of the requested size and MaxQueuedDocs when that limit is enabled. The writer consumes the IAsyncEnumerable with cancellation and sends each full batch through the same asynchronous channel.
This method does not commit each batch. Call CommitAsync according to the application's durability and visibility policy.
Document blocks
await writer.AddDocumentBlockAsync(
[childOne, childTwo, parent],
cancellationToken);
A block requires at least one child and one final parent. It is rejected when it exceeds MaxQueuedDocs under bounded backpressure because splitting it would break block-join adjacency.
Commit
await writer.CommitAsync(cancellationToken);
CommitAsync runs the synchronous commit manager on a thread-pool worker. Completion means the normal commit contract has completed, including durability when DurableCommits is enabled. A SearcherManager still needs to refresh before its readers observe the new generation.
Cancellation and failures
Cancellation can stop waiting to enqueue, stream enumeration, or a commit before its work begins. Work already accepted by the writer may have changed in-memory or flushed segment state even when a later operation throws.
An indexing call does not imply a commit. On exception:
- record the source checkpoint or failed document;
- decide whether to retry that unit;
- commit only the accepted work the application wants to retain;
- use
Rollback()when the whole uncommitted writer session must be abandoned.
Do not blindly retry a batch unless the source operation is idempotent or documents have stable update keys.
Parallel producers
Multiple producers may call the writer, but increasing caller parallelism beyond flush and storage capacity only increases queue pressure. Start with a small number of producers and observe MaxQueuedDocs, MaxQueuedBytes, flush latency, and pending merge bytes.
Use an application Channel<LeanDocument> when source acquisition itself needs a separate bound or prioritisation policy. The writer already provides its own downstream bound.
Sync or async
| Situation | Prefer |
|---|---|
| Dedicated worker thread, simple batch job | Synchronous methods |
| ASP.NET request or asynchronous message consumer | Async methods |
IAsyncEnumerable source |
AddDocumentsAsync |
| Atomic child and parent adjacency | AddDocumentBlock or AddDocumentBlockAsync |
Async improves caller scheduling, not codec or storage throughput by itself. Measure end-to-end indexing rate and allocation before increasing concurrency.