feat: Add async event processor - #472
Conversation
e7d9e77 to
0c83486
Compare
Implement the new AsyncEventProcessor interface with a concrete DefaultAsyncEventProcessor, matching the sync DefaultEventProcessor naming convention.
Triggers a flush and awaits delivery via a new inbox message, returning whether it completed within the timeout.
0c83486 to
ccb9c58
Compare
The async event delivery concurrency limiter no longer mirrors the sync FixedThreadPool's shape. BoundedTaskSet drops the unused name parameter and the thread vocabulary, reserves a slot synchronously at spawn (so a full set rejects rather than queues), and uses a done-callback plus asyncio.gather for cleanup and draining.
2230024 to
5ed9484
Compare
Remove the banner-style section headings; where they carried a useful note, capture it as a short class docstring instead.
| """A fixed-size pool of concurrent tasks that rejects jobs when its limit | ||
| is reached. Matches the contract of | ||
| ``ldclient.impl.fixed_thread_pool.FixedThreadPool``.""" | ||
| class BoundedTaskSet: |
There was a problem hiding this comment.
The AsyncWorkerPool was previously created to mirror the FixedThreadPool but some of the naming and params didn't seem to align with the async code.
…ction comments Rename drain() back to wait() (it awaits the in-flight tasks; it does not halt intake), simplify the job param to Callable[[], Coroutine], and remove banner-style section-heading comments from the async event/concurrency tests.
…cessors Move the event schema version constant into event_processor_common so both processors advertise the same X-LaunchDarkly-Event-Schema and can't drift.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 8c14ed7. Configure here.
| elif message.type == 'flush_and_wait': | ||
| self._trigger_flush() | ||
| await self._flush_workers.wait() | ||
| message.param.set() |
There was a problem hiding this comment.
flush_and_wait false success on saturation
Medium Severity
flush_and_wait treats completion of currently in-flight workers as successful delivery. If _trigger_flush cannot start a send because BoundedTaskSet is at its limit, events stay in the outbox while the handler still signals the waiter, so callers get True even though those events were never handed off.
Additional Locations (2)
Reviewed by Cursor Bugbot for commit 8c14ed7. Configure here.


Adds the async analytics event delivery component for the async SDK client, extracted from the async SDK implementation branch (SDK-60).
Stacked on #471 (AsyncConfig) — review that first. Until #471 merges this PR shows its commits too; after merge a rebase drops them out.
What's here
AsyncEventProcessorinterface +DefaultAsyncEventProcessorconcrete implementation, mirroring the syncEventProcessor/DefaultEventProcessorsplit.send_event/flushare sync;stopis a coroutine.event_processor_common.pyso the sync and async processors share buffering, output formatting, and dispatch logic.DefaultEventProcessorsuite over an injected mock aiohttp session.SDK-2769
feat: Add async event processor
Note
Medium Risk
Touches analytics delivery and refactors shared dispatch used by sync and async; risk is mitigated by extracting logic without intended behavior changes and broad async test coverage.
Overview
Adds
DefaultAsyncEventProcessorand an asyncEventDispatcherso the async SDK can queue, batch, flush, and POST analytics and diagnostic events overAsyncHTTPTransport, with the same inbox messaging, timers, gzip, retries, andflush_and_wait/ asyncstopbehavior as the sync processor.Shared non-I/O dispatch logic moves into
EventDispatcherBaseinevent_processor_common.py(_process_event, context dedup, debug handling,_handle_response), and the syncEventDispatchernow subclasses it.CURRENT_EVENT_SCHEMAis centralized there for both paths.Concurrent flush work on the async side uses
BoundedTaskSet(replacingAsyncWorkerPool) withtry_runfor bounded concurrency and backpressure. A large pytest suite mirrors the syncDefaultEventProcessortests against a mock aiohttp session.Reviewed by Cursor Bugbot for commit 8c14ed7. Bugbot is set up for automated code reviews on this repo. Configure here.