Add chunk tracing to .content#12889
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #12889 +/- ##
========================================
Coverage 98.95% 98.95%
========================================
Files 131 131
Lines 47824 48043 +219
Branches 2480 2491 +11
========================================
+ Hits 47324 47543 +219
Misses 376 376
Partials 124 124
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. |
Merging this PR will not alter performance
Comparing Footnotes
|
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
| if content and content.exception() is None: # type: ignore[truthy-bool] | ||
| set_exception(content, _CONNECTION_CLOSED_EXCEPTION) | ||
| if content: # type: ignore[truthy-bool] | ||
| if content.exception() is None: |
There was a problem hiding this comment.
need to check here if we could leak CancelledError
There was a problem hiding this comment.
it didn't check before so likely fine but something to check now that I'm looking at it
There was a problem hiding this comment.
No leak. except BaseException re-raises after close(); CancelledError still propagates. New aspect: cancelling a trace handler during a direct .content read now closes the response. Old read() path already closed on cancel. Confirm close-on-cancel acceptable for .content consumers.
| # read_nowait is sync but the hook is async; schedule it so the | ||
| # observability event still fires. | ||
| # TODO: Save and await this task. | ||
| asyncio.create_task(cb(chunk)) # type: ignore[unused-awaitable] |
There was a problem hiding this comment.
task can get gc'ed before complete
There was a problem hiding this comment.
nevermind, missed comment above it
There was a problem hiding this comment.
GC concern still open. Comment above explains scheduling, not GC-safety. Task reference dropped; may be collected mid-flight. Handler exceptions also dropped (unretrieved-task warning, no close()). TODO unresolved. Suggest holding a strong ref set with a done callback.
There was a problem hiding this comment.
This is only for the trace, and it didn't get a chance to trace at all before, so it's probably fine to leave for the moment. I'm hoping we get a task scheduler thing like aiojobs included into asyncio in the future.
|
|
||
| async def _fire_chunk_received(self, chunk: bytes) -> None: | ||
| cb = self._on_chunk_received | ||
| assert cb is not None |
There was a problem hiding this comment.
assuming this is only for type narrowing
There was a problem hiding this comment.
Yes. Type narrowing only. Callers guard self._on_chunk_received is not None before calling _fire_chunk_received. Assert never trips at runtime.
There was a problem hiding this comment.
Minor optimisation by having the check outside the function, so the no-traces case doesn't need to create a coroutine.
PR Review — Add chunk tracing to .contentSolid refactor that moves
🟡 Important1. Fire-and-forget task in read_nowait can be GC'd and swallows exceptions (`aiohttp/streams.py`, L533-541)
Three gaps versus the async paths:
Minimal fix: keep a module/instance-level Checklist
Silent Failure Analysis🟠 **HIGH** — fire-and-forget async task (`aiohttp/streams.py:536-541`)Risk: The scheduled task is never referenced, awaited, or given a done-callback, so any exception from the trace handler (including the Fix: Store the task in a strong reference set (e.g. Automated review by Kōan (Claude) |
Fixes #5324.