Fix cancelled GenAI wrapper finalization - #656
Conversation
There was a problem hiding this comment.
Warning
Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.
Pull request overview
Fixes cancellation handling in GenAI telemetry wrappers so cancellations (e.g., asyncio.CancelledError) properly finalize spans/invocations before being re-raised.
Changes:
- Broaden exception handling from
ExceptiontoBaseExceptionin shared stream wrappers/managers to capture cancellation paths. - Update multiple vendor instrumentations (OpenAI/Anthropic/Portkey/Qwen Agent/Smolagents) to record failures on cancellation.
- Add unit tests covering cancellation behavior and add changelog entries.
Reviewed changes
Copilot reviewed 15 out of 15 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| util/opentelemetry-util-genai/src/opentelemetry/util/genai/stream.py | Catch BaseException in stream wrapper/manager paths to ensure telemetry finalization on cancellation. |
| util/opentelemetry-util-genai/tests/test_stream.py | Add cancellation-focused tests for stream wrappers and manager wrappers. |
| util/opentelemetry-util-genai/.changelog/656.fixed | Document cancellation finalization behavior change for shared GenAI stream utilities. |
| instrumentation/opentelemetry-instrumentation-genai-smolagents/src/opentelemetry/instrumentation/genai/smolagents/patch.py | Record failed invocations for cancellations while creating stream wrappers. |
| instrumentation/opentelemetry-instrumentation-genai-smolagents/.changelog/656.fixed | Document Smolagents cancellation failure recording. |
| instrumentation/opentelemetry-instrumentation-genai-qwen-agent/src/opentelemetry/instrumentation/genai/qwen_agent/patch.py | Record failed tool invocations for cancellations. |
| instrumentation/opentelemetry-instrumentation-genai-qwen-agent/.changelog/656.fixed | Document Qwen Agent cancellation failure recording. |
| instrumentation/opentelemetry-instrumentation-genai-portkey/src/opentelemetry/instrumentation/genai/portkey/patch.py | Record failed sync/async invocations for cancellations. |
| instrumentation/opentelemetry-instrumentation-genai-portkey/.changelog/656.fixed | Document Portkey cancellation failure recording. |
| instrumentation/opentelemetry-instrumentation-genai-openai/src/opentelemetry/instrumentation/genai/openai/patch.py | Record failed OpenAI invocations for cancellations in chat/embeddings wrappers. |
| instrumentation/opentelemetry-instrumentation-genai-openai/src/opentelemetry/instrumentation/genai/openai/patch_responses.py | Record failed OpenAI responses invocations for cancellations (sync + async). |
| instrumentation/opentelemetry-instrumentation-genai-openai/tests/test_embedding_invocation_unit.py | Add tests asserting cancellation is recorded and re-raised for embeddings (sync + async). |
| instrumentation/opentelemetry-instrumentation-genai-openai/.changelog/656.fixed | Document OpenAI cancellation failure recording. |
| instrumentation/opentelemetry-instrumentation-genai-anthropic/src/opentelemetry/instrumentation/genai/anthropic/patch.py | Record failed Anthropic invocations for cancellations (sync + async). |
| instrumentation/opentelemetry-instrumentation-genai-anthropic/.changelog/656.fixed | Document Anthropic cancellation failure recording. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| _set_response_properties(chat_invocation, result, capture_content) | ||
| chat_invocation.stop() | ||
| return result | ||
| except Exception as error: | ||
| except BaseException as error: | ||
| chat_invocation.fail(error) | ||
| raise |
| def close(self) -> None: | ||
| try: | ||
| self._self_stream.close() | ||
| except Exception as error: | ||
| except BaseException as error: | ||
| self._finalize_failure(error) | ||
| raise |
| spans = span_exporter.get_finished_spans() | ||
| assert len(spans) == 1 | ||
| span = spans[0] | ||
| assert span.attributes["error.type"] == "asyncio.exceptions.CancelledError" |
lmolkova
left a comment
There was a problem hiding this comment.
thanks for working on this!
it seems there is still except Exception in bedrock and google-genai - could you please update them too?
And please update agents.md in instrumentation folder and copilot review instructions for instrumentations to suggest BaseException and to flag narrow ones.
dba8394 to
379ffca
Compare
Pull request dashboard statusWaiting on the author · refreshed 2026-09-09 04:38 UTC Respond to 4 review items (e.g. link a commit, explain why not, ask a follow-up): Status above doesn't look right?
|
Fixes #646.
This widens telemetry-finalizing wrapper handlers from
ExceptiontoBaseExceptionso cancellations such asasyncio.CancelledErrorfail and end invocations before being re-raised. It covers shared stream wrappers/managers plus OpenAI, Anthropic, Bedrock, Portkey, Qwen Agent, and Google GenAI hand-written wrapper paths.Also updates instrumentation reviewer instructions to flag telemetry-finalizing
except Exceptionhandlers.Known gaps: none.