Skip to content

Async, notebooks & logging

Every call has two forms

Each operation and service ships a sync form and an a-prefixed async form — same signature, same behavior:

Sync Async
parse aparse
classify aclassify
split asplit
extract aextract
ingest aingest
retrieve aretrieve

Use the async forms anywhere an event loop is already running — web handlers, agents, concurrent batch jobs:

from ingestlib.services import aingest, aretrieve

result = await aingest("report.pdf")
hits = await aretrieve("what changed year over year?")

Internally the pipeline is async-first: chunk embedding runs bounded-parallel, and blocking store/artifact calls are kept off the event loop.

Notebooks

Jupyter runs an event loop, so the sync forms refuse with an error that names the fix:

ingest("report.pdf")
# RuntimeError: you are inside a running event loop (a notebook?) —
# call `await aingest(...)` instead of the sync form

Notebooks can await at the top level — just use the async form directly:

result = await aingest("report.pdf")

Concurrency notes

  • Safe: concurrent aretrieve() calls; ingesting different documents concurrently.
  • Pointless: ingesting the same file concurrently (checksum dedup makes one of them a no-op, but they'll race the same work first).
  • Parse itself processes one document's pages as a unit — parallelism belongs at the document level.

Logging

ingestlib logs every stage to stderr through its own logger namespace — INFO shows real progress (per-stage timing, chunk counts, upsert sizes):

14:32:07 INFO  ingestlib.operations.parse.pipeline   parse start: report.pdf (24 pages)
14:32:48 INFO  ingestlib.services.ingest.ingestor    ingest done: report.pdf → research_paper, 24 chunk(s) in 41.2s

Control it with environment variables:

Variable Effect
INGESTLIB_LOG_LEVEL DEBUG · INFO (default) · WARNING · ERROR
INGESTLIB_LOG_THIRD_PARTY=1 also raise SDK loggers (httpx, botocore, …) to the same level
INGESTLIB_LOG_COLOR=0 disable ANSI colors (auto-detects TTY otherwise)

Or reconfigure at runtime — idempotent, never duplicates handlers:

from ingestlib.utils.logger import configure

configure(level="DEBUG")

Noisy third-party SDKs are quieted to WARNING by default — but a level your application set explicitly is always respected, and ingestlib's logger never propagates into your root logger's handlers.


Next: Troubleshooting — the error catalog.