Skip to content

Commit 6b358f0

Browse files
docs(hosting): distinguish force_flush and shutdown in async-resolver caveat
In opentelemetry-sdk 1.39, force_flush() exports on the calling thread, so an async resolver fails when it is called from a running event loop. shutdown() runs its final export on the batch worker thread and only blocks the caller. The README previously said both would fail. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 5cbf5f6b-cc40-4b7e-a591-65848db73a12
1 parent 1e83d75 commit 6b358f0

1 file changed

Lines changed: 14 additions & 7 deletions

File tree

  • libraries/microsoft-agents-a365-observability-hosting

‎libraries/microsoft-agents-a365-observability-hosting/README.md‎

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,20 @@ acquisition failures, isolates entries by `(agent_id, tenant_id)`, respects JWT
3838
expiry with refresh skew, and uses a fallback TTL for opaque tokens.
3939

4040
If you use an async exporter resolver, `_Agent365Exporter` runs it with
41-
`asyncio.run` on the BatchSpanProcessor worker thread. Create async clients
42-
inside that resolver; do not reuse `aiohttp` or `azure.identity.aio` clients
43-
bound to your app's event loop. Also, `force_flush()` and `shutdown()` called
44-
from inside a running event loop cannot await an async resolver, so that export
45-
fails with a logged error; call them with `await asyncio.to_thread(...)`. A
46-
synchronous, thread-safe cached resolver avoids both constraints and is the
47-
pattern used by the Agent365-Samples Python samples.
41+
`asyncio.run` on the thread that performs the export:
42+
43+
- Scheduled batch exports and the final export during `shutdown()` run on the
44+
BatchSpanProcessor worker thread. `shutdown()` still blocks its caller until
45+
that export finishes.
46+
- `force_flush()` exports on the calling thread. If you call it from inside a
47+
running event loop, the async resolver can't be awaited and that export
48+
fails with a logged error.
49+
50+
Create async clients inside the resolver; don't reuse `aiohttp` or
51+
`azure.identity.aio` clients bound to your app's event loop. From async code,
52+
call `force_flush()` and `shutdown()` with `await asyncio.to_thread(...)`. A
53+
synchronous, thread-safe cached resolver avoids these event-loop restrictions
54+
and is the pattern the Agent365-Samples Python samples use.
4855
Call `refresh_observability_token` only from the exporter's `token_resolver`;
4956
its per-key locks are `asyncio.Lock`s, so do not also refresh the same cache
5057
instance from your app's own event loop or threads.

0 commit comments

Comments
 (0)