Store SDK runtime helpers in the current execution context.
Why context variables are used
An application can run several SDK instances at the same time. The instances can also use the same event loop. A thread-local variable cannot distinguish tasks that share one thread. A normal module variable would let one SDK replace the value for another SDK.
contextvars.ContextVar stores a different value for each execution
context. Each SDK task therefore gets the scheduler and bridge of its own
runtime. Nested calls are also safe. A nested call can set a new value and can
then restore the previous value with a context token.
How values are retained
The runtime sets both variables before it starts SDK work. A context keeps the values across each await. By default, a new asyncio task copies the current context when code creates the task. The child task therefore keeps the same runtime helpers after its parent continues or resets its own values.
Creating a coroutine object does not copy the current context. A coroutine uses the context of the task that runs it. To retain the current bindings, create a task while the bindings are active. You can also submit the coroutine through the active scheduler.
The runtime resets both variables in a finally block when submitted work ends. Synchronous SDK callbacks use the same set-and-reset procedure. The stored values are bound methods, so an inherited context keeps its SDK runtime alive until that context is released.
Limitations
The ContextVar objects are module-level keys. Their values are not
process-wide mutable values, but code outside an active SDK context gets
None.
Context inheritance does not register a raw task with the SDK runtime. Code
that calls asyncio.create_task directly can keep the runtime helpers.
On a caller-supplied loop, this untracked task can outlive SDK close. On an
SDK-owned loop, final loop shutdown cancels remaining tasks, but normal SDK
submission tracking still omits the raw task. Use the active
task_scheduler or nebius.aio.channel.Channel.bg_task for work that
SDK close must track.
Code can override the copied context when it creates a task. Context values
also do not propagate automatically to an arbitrary worker thread.
asyncio.to_thread copies the current context, but
asyncio.loop.run_in_executor does not.
The bridge can identify an asyncio.Future and its owner loop. It
cannot identify hidden loop ownership in every custom awaitable. A custom
awaitable with loop-affine state must provide its own cross-loop behavior or
must be used on the event loop that owns that state. A loop-neutral custom
awaitable can be created and used on any loop.
| Function | bridge |
Make an awaitable usable by the current SDK runtime. |
| Function | close |
Close only a fresh coroutine rejected by a synchronous adapter. |
| Function | dispose |
Release awaitable work whose SDK wrapper provably never started. |
| Type Alias | |
Function that adapts an awaitable for the current SDK runtime. |
| Type Alias | |
Function that submits tracked work to the current SDK runtime. |
| Variable | awaitable |
Awaitable bridge for the current execution context. |
| Variable | task |
Tracked-work scheduler for the current execution context. |
Make an awaitable usable by the current SDK runtime.
This function reads awaitable_bridge from the current context. It does not read a process-wide runtime. Return awaitable without a change when no runtime bridge is active.
The active bridge converts a foreign-loop asyncio.Future to a
cross-loop awaitable. It does not change a future that already belongs to
the SDK loop. It also does not inspect custom awaitables for hidden loop
ownership.
| Parameters | |
awaitable:Awaitable[ | Awaitable to examine. |
| Returns | |
Awaitable[ | The original awaitable or a cross-loop awaitable. |
Close only a fresh coroutine rejected by a synchronous adapter.
A synchronous call made from an event loop or SDK executor worker cannot block safely. The adapter owns disposal of a coroutine object created only for that rejected call, so closing it prevents an unawaited-coroutine warning. It does not own an already scheduled Future, Task, concurrent future, cross-loop handle, or opaque custom awaitable. Other waiters can share these values, so the adapter must not change them.
| Parameters | |
awaitable:Awaitable[ | Input rejected before a synchronous wait starts. |
| Returns | |
bool | True when a native coroutine object was closed. |
Release awaitable work whose SDK wrapper provably never started.
A pending foreign asyncio.Future must be cancelled through its
owner loop; calling it directly from an SDK or caller thread is not
asyncio-safe. A terminal failed Future has its exception retrieved on that
loop because the unstarted wrapper owns its observation. Retrieving the
exception does not prevent later awaits from raising it. A concurrent
future and an SDK cross-loop handle provide thread-safe cancellation.
Native coroutine objects instead use close() so Python does not report
that they were never awaited.
A custom awaitable is never closed implicitly on an arbitrary submission, cancellation, or shutdown thread. It must provide the private SDK _cancel_unstarted_threadsafe hook when it supports thread-safe disposal. Otherwise its hidden loop ownership is unknown and disposal is skipped. A foreign asyncio owner loop must remain running through dispatch, as required by the cross-loop contract. Exceptions raised by custom disposal hooks are suppressed so cleanup does not replace the lifecycle or submission error that caused disposal.
| Parameters | |
awaitable:Awaitable[ | Never-started caller work to release. |
| Returns | |
bool | True when disposal completed or was accepted for dispatch; otherwise False. |
Awaitable bridge for the current execution context.
The value is normally
nebius.aio._runtime.AsyncRuntime.bridge_awaitable. It is a bound method
for one SDK runtime.
Tracked-work scheduler for the current execution context.
The value is normally
nebius.aio._runtime.AsyncRuntime.submit_background. It is a bound
method for one SDK runtime.