Skip to content

v0.1.4 — batch() correctness, thread-safe handler, defensive storage

Choose a tag to compare

@dakshtrehan dakshtrehan released this 19 Apr 05:17
· 17 commits to main since this release

The correctness release. If you have been running chain.batch([...]) or sharing a handler across concurrent chain.invoke calls, upgrade immediately.

See CHANGELOG.md for the full entry.

The bug this fixes

Prior to v0.1.4, both handlers kept per-invocation state on the instance. With chain.batch([q1, q2, q3]) or concurrent invokes on a shared handler, only the outermost chain's record would save, and fields bled across runs — the first query could be paired with the last query's answer. For a compliance library, silent audit loss with fabricated pairings is the most dangerous possible failure mode.

What shipped

  • Per-run state in the LangChain handler. State now lives in self._runs[run_id] = _RunState, guarded by a threading.Lock, with parent_run_id resolving to the tracked root via self._run_parents. Each _RunState tracks its descendants for O(1) cleanup on chain end.
  • Per-trace state in the LlamaIndex handler. State keyed by trace_id in self._traces, with active trace routed via threading.local so the trace_id-less on_event_* callbacks reach the correct state.
  • Defensive storage.save(). Both handlers wrap self.storage.save(record) in try/except. A misbehaving custom storage can no longer kill a chain or leak pending state.
  • New env var RAGCOMPLIANCE_MAX_PENDING_RUNS (default 10000): soft cap on in-flight root run states with oldest-first eviction. Guards against memory leaks if on_chain_end is never delivered.

Test suite: 145 passed (up from 126)

19 new regression tests covering:

  • 3-query batch with correctly-paired records
  • 10 and 20 concurrent threads on a shared handler
  • Nested LCEL chains saving exactly once
  • Inner events routing to root state
  • Interleaved event ordering
  • Soft-cap eviction with descendant cleanup
  • Raising storage not killing the chain
  • on_chain_end p50 hot-path microbench
  • Bad env var values falling back to default
  • LlamaIndex: 10 concurrent traces producing distinct records

Install

pip install --upgrade ragcompliance==0.1.4

Upgrading from 0.1.3

No breaking API changes for normal users. If you were reaching into handler internals (e.g. handler._query), those attributes no longer exist — state now lives in handler._runs[run_id]. The public callback API is unchanged.