Async Operations
When to Use
Use this skill when the user asks about async rendering, non-blocking operations, polling, timeouts, or parallel rendering.
Inputs
Resolve inputs in this order: existing repository files and referenced snippets, explicit user request, then broader agent context.
- Target API surface: Python, C/C++, or both.
- Operation type: USD load/reference, render step, reset, clone, query, attribute read/write, or result fetch.
- Desired control flow: blocking wait, non-blocking poll, finite timeout, progress reporting, or two-stage result fetching.
- Language-specific handle involved: Python
Operation, pending fetch object, C ovrtx_op_id_t, or result handle.
- Repository source snippets referenced below. Treat these snippets as the API source of truth.
Prerequisites
- Use an ovrtx checkout that contains the referenced examples and docs tests.
- Read the relevant
> **Source:** snippet before writing or explaining API usage.
- Know whether the async operation completes directly or returns a second-phase object that must be fetched after wait.
Instructions
- Identify whether the caller needs blocking execution, non-blocking polling, progress reporting, or two-phase result fetching.
- In Python, use the two-stage pattern for result-bearing operations: call the
_async method, wait() for a pending fetch object, then fetch() the final result.
- For non-blocking Python waits, call
wait(timeout_ns=0) first and handle None as "still running"; use a finite or infinite wait only when the workflow is ready to block.
- In C, treat every enqueue result as asynchronous: check the enqueue status, wait on
op_index, inspect operation errors, then fetch or destroy result handles as required.
- When changing code, run the narrow async/status docs test or example that owns the snippet whenever practical.
Output Format
- For explanations, cite the relevant API names, source snippets, and caveats.
- For code changes, summarize the files changed, snippets affected, and validation run.
Scripts
This skill has no scripts.
Limitations
- The referenced snippets remain the source of truth; update or add tested snippets before documenting new API usage.
Overview
All ovrtx enqueue operations (open_usd, add_usd_reference, step, write_attribute, etc.) are internally asynchronous and stream-ordered. In Python, the default methods (e.g., open_usd, add_usd_reference, step) block until completion. The _async variants return Operation objects that support polling and custom timeouts.
In C, all enqueue calls return immediately with an ovrtx_op_id_t that can be polled or waited on.
Python
Non-blocking USD load
Source: tests/docs/python/test_support_api.py snippet doc-open-usd-async
The same polling pattern applies to open_usd_async and add_usd_reference_async — call op.wait(timeout_ns=0) to poll, or op.wait() to block.
Non-blocking step with two-stage timeout
Source: tests/docs/python/test_camera_sensors.py snippet doc-step-async
Infinite wait (default)
Source: examples/python/minimal/main.py snippet step
The synchronous step() is equivalent to step_async().wait().
step_async returns Operation[PendingFetch[RenderProductSetOutputs]]
In 0.3.0 the Python RendererResult return type was removed; step_async() now follows the standard two-phase Operation / PendingFetch lifecycle.
Source: tests/docs/python/test_camera_sensors.py snippet doc-step-async
Query progress on long-running operations
Operation.query_status() returns a point-in-time OperationStatus (state, progress, resource counters). Safe to call repeatedly while the op is PENDING; it becomes unavailable after wait() consumes the operation.
Source: tests/docs/python/test_base.py snippet doc-operation-status
C
Poll with zero timeout
Source: examples/c/minimal/main.cpp snippet load-usd-and-wait
The load snippet demonstrates polling with ovrtx_timeout_t{0}.
Poll loop with sleep
Source: examples/c/minimal/main.cpp snippet load-usd-and-wait
Block indefinitely
Source: examples/c/minimal/main.cpp snippet step-renderer
Uses ovrtx_timeout_infinite to block until completion.
Check for errors after wait
Source: examples/c/minimal/main.cpp snippet load-usd-and-wait
Check wait_result.num_error_ops after any ovrtx_wait_op call.
Query operation progress
For long-running operations (e.g., USD loading), call ovrtx_query_op_status(renderer, op_id, &status) to get progress and named resource counters, then ovrtx_release_op_status(renderer, &status) to release the returned pointers. Counter names are operation-dependent (e.g., "shaders", "textures", "materials" during USD loading). A total of 0 means the total is not yet known.
Source: examples/python/status-queries/main.py snippet wait-operation-with-status
Source: examples/c/status-queries/main.cpp snippet wait-operation-with-status-c
For the full pattern, use the status-queries skill.
Key Types / Functions
| Python |
C |
Operation.wait(timeout_ns=None) |
ovrtx_wait_op(renderer, op_id, timeout, &wait_result) |
Operation.wait(timeout_ns=0) |
ovrtx_wait_op with timeout.time_out_ns = 0 |
Operation.wait() → PendingFetch, then .fetch() |
ovrtx_wait_op + per-op fetch call (ovrtx_fetch_results / ovrtx_fetch_read_result / ovrtx_fetch_query_results) |
Operation.query_status() → OperationStatus |
ovrtx_query_op_status(renderer, op_id, &status) + ovrtx_release_op_status(renderer, &status) |
RuntimeError on failure |
wait_result.num_error_ops > 0 |
| Python copies status into dataclasses |
ovrtx_release_op_status(renderer, &status) -- must call after each successful query |
C timeout constants:
ovrtx_timeout_t{0} -- non-blocking poll
ovrtx_timeout_infinite -- block indefinitely
ovrtx_timeout_t{5000000000} -- 5 seconds in nanoseconds
C wait result fields:
error_op_ids / num_error_ops -- operations that errored since last wait
lowest_pending_op_id -- 0 if all operations complete, nonzero if still pending
Troubleshooting
- In Python,
Operation.wait() with no arguments blocks forever -- this is usually what you want.
wait(timeout_ns=0) returns None on timeout, which is distinct from a successful result. For operations that return None on success (like reset_stage), use the Operation object's state to distinguish.
- In Python, call
Operation.query_status() before Operation.wait() completes; completed operations release their wait-phase context.
- In C,
ovrtx_wait_op waits for all operations up to and including the given op_id, not just that single operation.
- In C, check the
ovrtx_wait_op return status before interpreting wait_result fields.
- In C, release each successful
ovrtx_query_op_status() result with ovrtx_release_op_status().
- Error strings from
ovrtx_get_last_op_error() are valid only until the next ovrtx_wait_op call on the same thread.
In Attached Mode (ovrtx 0.4+)
When ovrtx is attached to ovstage, the write side of the async model moves to
ovstage's ordinal-keyed submit/observe: ovstage enqueues return an op_index
immediately, and ordinal sealing (ovstage_advance_write_floor) is what makes
writes observable. ovrtx observes the sealed state by passing the same ordinal
to ovrtx_step_with_stage(..., ordinal) and
ovrtx_update_from_stage(ordinal). See ovstage
skills/cpu-ahead-gpu-async/SKILL.md for the authoritative async model.
See docs/core/ovstage_integration.rst, skills/update-0_3-0_4-c/SKILL.md and skills/update-0_3-0_4-python/SKILL.md.
References
- Use the
> **Source:** directives in this skill to locate tested snippets before reusing API patterns.
- Keep related skills, docs, and snippets synchronized when changing the workflow.
1---2# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.3# SPDX-License-Identifier: LicenseRef-NvidiaProprietary4#5# NVIDIA CORPORATION, its affiliates and licensors retain all intellectual6# property and proprietary rights in and to this material, related7# documentation and any modifications thereto. Any use, reproduction,8# disclosure or distribution of this material and related documentation9# without an express license agreement from NVIDIA CORPORATION or10# its affiliates is strictly prohibited.11name: async-operations12description: >13 Asynchronous operation patterns including polling, timeouts, and non-blocking14 workflows. Use when user asks about async rendering, non-blocking operations,15 polling, timeouts, or parallel rendering.16license: LicenseRef-NvidiaProprietary17author: NVIDIA ovrtx18tags:19 - ovrtx20 - async21 - operations22tools:23 - Read24 - Grep25---2627# Async Operations2829## When to Use3031Use this skill when the user asks about async rendering, non-blocking operations, polling, timeouts, or parallel rendering.3233## Inputs3435Resolve inputs in this order: existing repository files and referenced snippets, explicit user request, then broader agent context.3637- Target API surface: Python, C/C++, or both.38- Operation type: USD load/reference, render step, reset, clone, query, attribute read/write, or result fetch.39- Desired control flow: blocking wait, non-blocking poll, finite timeout, progress reporting, or two-stage result fetching.40- Language-specific handle involved: Python `Operation`, pending fetch object, C `ovrtx_op_id_t`, or result handle.41- Repository source snippets referenced below. Treat these snippets as the API source of truth.4243## Prerequisites4445- Use an ovrtx checkout that contains the referenced examples and docs tests.46- Read the relevant `> **Source:**` snippet before writing or explaining API usage.47- Know whether the async operation completes directly or returns a second-phase object that must be fetched after wait.4849## Instructions50511. Identify whether the caller needs blocking execution, non-blocking polling, progress reporting, or two-phase result fetching.522. In Python, use the two-stage pattern for result-bearing operations: call the `_async` method, `wait()` for a pending fetch object, then `fetch()` the final result.533. For non-blocking Python waits, call `wait(timeout_ns=0)` first and handle `None` as "still running"; use a finite or infinite wait only when the workflow is ready to block.544. In C, treat every enqueue result as asynchronous: check the enqueue status, wait on `op_index`, inspect operation errors, then fetch or destroy result handles as required.555. When changing code, run the narrow async/status docs test or example that owns the snippet whenever practical.5657## Output Format5859- For explanations, cite the relevant API names, source snippets, and caveats.60- For code changes, summarize the files changed, snippets affected, and validation run.6162## Scripts6364This skill has no scripts.6566## Limitations6768- The referenced snippets remain the source of truth; update or add tested snippets before documenting new API usage.6970## Overview7172All ovrtx enqueue operations (`open_usd`, `add_usd_reference`, `step`, `write_attribute`, etc.) are internally asynchronous and stream-ordered. In Python, the default methods (e.g., `open_usd`, `add_usd_reference`, `step`) block until completion. The `_async` variants return `Operation` objects that support polling and custom timeouts.7374In C, all enqueue calls return immediately with an `ovrtx_op_id_t` that can be polled or waited on.7576## Python7778### Non-blocking USD load7980> **Source:** `tests/docs/python/test_support_api.py` snippet `doc-open-usd-async`81>82> The same polling pattern applies to `open_usd_async` and `add_usd_reference_async` — call `op.wait(timeout_ns=0)` to poll, or `op.wait()` to block.8384### Non-blocking step with two-stage timeout8586> **Source:** `tests/docs/python/test_camera_sensors.py` snippet `doc-step-async`8788### Infinite wait (default)8990> **Source:** `examples/python/minimal/main.py` snippet `step`91>92> The synchronous `step()` is equivalent to `step_async().wait()`.9394### step_async returns Operation[PendingFetch[RenderProductSetOutputs]]9596In 0.3.0 the Python `RendererResult` return type was removed; `step_async()` now follows the standard two-phase `Operation` / `PendingFetch` lifecycle.9798> **Source:** `tests/docs/python/test_camera_sensors.py` snippet `doc-step-async`99100### Query progress on long-running operations101102`Operation.query_status()` returns a point-in-time `OperationStatus` (state, progress, resource counters). Safe to call repeatedly while the op is `PENDING`; it becomes unavailable after `wait()` consumes the operation.103104> **Source:** `tests/docs/python/test_base.py` snippet `doc-operation-status`105106## C107108### Poll with zero timeout109110> **Source:** `examples/c/minimal/main.cpp` snippet `load-usd-and-wait`111>112> The load snippet demonstrates polling with `ovrtx_timeout_t{0}`.113114### Poll loop with sleep115116> **Source:** `examples/c/minimal/main.cpp` snippet `load-usd-and-wait`117118### Block indefinitely119120> **Source:** `examples/c/minimal/main.cpp` snippet `step-renderer`121>122> Uses `ovrtx_timeout_infinite` to block until completion.123124### Check for errors after wait125126> **Source:** `examples/c/minimal/main.cpp` snippet `load-usd-and-wait`127>128> Check `wait_result.num_error_ops` after any `ovrtx_wait_op` call.129130### Query operation progress131132For long-running operations (e.g., USD loading), call `ovrtx_query_op_status(renderer, op_id, &status)` to get progress and named resource counters, then `ovrtx_release_op_status(renderer, &status)` to release the returned pointers. Counter names are operation-dependent (e.g., `"shaders"`, `"textures"`, `"materials"` during USD loading). A `total` of 0 means the total is not yet known.133134> **Source:** `examples/python/status-queries/main.py` snippet `wait-operation-with-status`135>136> **Source:** `examples/c/status-queries/main.cpp` snippet `wait-operation-with-status-c`137138For the full pattern, use the `status-queries` skill.139140## Key Types / Functions141142| Python | C |143|--------|---|144| `Operation.wait(timeout_ns=None)` | `ovrtx_wait_op(renderer, op_id, timeout, &wait_result)` |145| `Operation.wait(timeout_ns=0)` | `ovrtx_wait_op` with `timeout.time_out_ns = 0` |146| `Operation.wait()` → `PendingFetch`, then `.fetch()` | `ovrtx_wait_op` + per-op fetch call (`ovrtx_fetch_results` / `ovrtx_fetch_read_result` / `ovrtx_fetch_query_results`) |147| `Operation.query_status()` → `OperationStatus` | `ovrtx_query_op_status(renderer, op_id, &status)` + `ovrtx_release_op_status(renderer, &status)` |148| `RuntimeError` on failure | `wait_result.num_error_ops > 0` |149| Python copies status into dataclasses | `ovrtx_release_op_status(renderer, &status)` -- must call after each successful query |150151C timeout constants:152- `ovrtx_timeout_t{0}` -- non-blocking poll153- `ovrtx_timeout_infinite` -- block indefinitely154- `ovrtx_timeout_t{5000000000}` -- 5 seconds in nanoseconds155156C wait result fields:157- `error_op_ids` / `num_error_ops` -- operations that errored since last wait158- `lowest_pending_op_id` -- 0 if all operations complete, nonzero if still pending159160## Troubleshooting161162- In Python, `Operation.wait()` with no arguments blocks forever -- this is usually what you want.163- `wait(timeout_ns=0)` returns `None` on timeout, which is distinct from a successful result. For operations that return `None` on success (like `reset_stage`), use the `Operation` object's state to distinguish.164- In Python, call `Operation.query_status()` before `Operation.wait()` completes; completed operations release their wait-phase context.165- In C, `ovrtx_wait_op` waits for all operations up to and including the given `op_id`, not just that single operation.166- In C, check the `ovrtx_wait_op` return status before interpreting `wait_result` fields.167- In C, release each successful `ovrtx_query_op_status()` result with `ovrtx_release_op_status()`.168- Error strings from `ovrtx_get_last_op_error()` are valid only until the next `ovrtx_wait_op` call on the same thread.169170## In Attached Mode (ovrtx 0.4+)171172When ovrtx is attached to ovstage, the write side of the async model moves to173ovstage's ordinal-keyed submit/observe: ovstage enqueues return an ``op_index``174immediately, and ordinal sealing (``ovstage_advance_write_floor``) is what makes175writes observable. ovrtx observes the sealed state by passing the same ordinal176to ``ovrtx_step_with_stage(..., ordinal)`` and177``ovrtx_update_from_stage(ordinal)``. See ovstage178``skills/cpu-ahead-gpu-async/SKILL.md`` for the authoritative async model.179180See `docs/core/ovstage_integration.rst`, `skills/update-0_3-0_4-c/SKILL.md` and `skills/update-0_3-0_4-python/SKILL.md`.181182## References183184- Use the `> **Source:**` directives in this skill to locate tested snippets before reusing API patterns.185- Keep related skills, docs, and snippets synchronized when changing the workflow.