Commit f68b22f
authored
feat(server): add async context manager support to EventQueue (#743)
# Description
Thank you for opening a Pull Request!
Before submitting your PR, there are a few things you can do to make
sure it goes smoothly:
- [x] Follow the [`CONTRIBUTING`
Guide](https://github.com/a2aproject/a2a-python/blob/main/CONTRIBUTING.md).
- [x] Make your Pull Request title in the
<https://www.conventionalcommits.org/> specification.
- Important Prefixes for
[release-please](https://github.com/googleapis/release-please):
- `fix:` which represents bug fixes, and correlates to a
[SemVer](https://semver.org/) patch.
- `feat:` represents a new feature, and correlates to a SemVer minor.
- `feat!:`, or `fix!:`, `refactor!:`, etc., which represent a breaking
change (indicated by the `!`) and will result in a SemVer major.
- [x] Ensure the tests and linter pass (Run `bash scripts/format.sh`
from the repository root to format)
- [x] Appropriate docs were updated (if necessary)
Fixes #720 🦕
## Problem
`EventQueue` has a sophisticated `close()` with graceful/immediate
modes, child propagation, and cross-version handling — but doesn't
support `async with`. Server-side code must use explicit `try/finally`
or risk leaking resources on exceptions:
```python
queue = EventQueue()
try:
await queue.enqueue_event(event)
...
finally:
await queue.close()
```
## Fix
Add `__aenter__` and `__aexit__` as concrete methods on `EventQueue`:
* `__aenter__` returns `Self` (via `typing_extensions`).
* `__aexit__` delegates to `close()` with default `immediate=False`
(graceful). Code needing immediate shutdown can still call `await
queue.close(immediate=True)` explicitly.
This enables the idiomatic pattern:
```python
async with EventQueue() as queue:
await queue.enqueue_event(event)
...
# close() called automatically, even on exceptions
```
Unlike the client-side hierarchy where `__aenter__`/`__aexit__` were
lifted to the abstract `Client` (#719), `EventQueue` is a concrete class
with no abstract base above it — `QueueManager` manages queue lifecycles
by task ID but does not wrap or extend `EventQueue`. This is the correct
and only place for these methods.
Non-breaking, additive change. Manual `close()` and `try/finally`
continue to work as before.
Follows the pattern established in `ClientTransport` (#682),
`BaseClient` (#688), and `Client` (#719).
## Tests
Two tests added to `tests/server/events/test_event_queue.py`, following
the same approach as `ClientTransport` and `BaseClient`.1 parent fd0a1bd commit f68b22f
2 files changed
Lines changed: 39 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2 | 2 | | |
3 | 3 | | |
4 | 4 | | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
5 | 9 | | |
6 | 10 | | |
7 | 11 | | |
| |||
43 | 47 | | |
44 | 48 | | |
45 | 49 | | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
46 | 63 | | |
47 | 64 | | |
48 | 65 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
78 | 78 | | |
79 | 79 | | |
80 | 80 | | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
81 | 103 | | |
82 | 104 | | |
83 | 105 | | |
| |||
0 commit comments