Skip to content

Async Request-Response for Bulk Variation Registration#480

Merged
ehclark merged 21 commits into
mainfrom
variations-high-perf
Jun 24, 2026
Merged

Async Request-Response for Bulk Variation Registration#480
ehclark merged 21 commits into
mainfrom
variations-high-perf

Conversation

@ehclark

@ehclark ehclark commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Async Request-Response for Bulk Variation Registration

Summary

This PR adds asynchronous request-response support to the PUT /variations endpoint, following the same async request-reply pattern already used by the /vcf endpoints. Large batches of variation registrations can now be submitted asynchronously via PUT /variations?run_async=true, returning a 202 Accepted with a run_id that the client polls at GET /variations/{run_id} until the result is ready.

As part of this work, the shared async task lifecycle logic (Celery state machine handling, run-ID validation, async-enabled checks) was extracted from the VCF router into a new reusable module, and the VCF router was refactored to consume it.

Key Changes

New module: src/anyvar/restapi/async_utils.py
Extracts three reusable helpers previously inline in the VCF router:

  • check_async_enabled() — returns an ErrorResponse (400) if async prerequisites are missing
  • validate_run_id_available() — rejects duplicate run_id values that are still active in Celery
  • resolve_async_task_status() — encapsulates the full Celery task state machine: SUCCESS → call on_success callback and forget; FAILURE → extract error code, optional cleanup, forget; PENDING → poll up to 5s then 404; SENT → 202 with Retry-After

Modified: src/anyvar/restapi/variations_router.py

  • PUT /variations gains run_async (bool) and run_id (optional str) query parameters. When run_async=true, the request body is serialized and dispatched to a Celery task, returning a RunStatusResponse with Location and Retry-After headers.
  • New GET /variations/{run_id} endpoint delegates to resolve_async_task_status() to return status or completed results.

Modified: src/anyvar/restapi/vcf_router.py
Refactored to import and use the shared helpers from async_utils instead of inline implementations.

New Celery task: register_variations in src/anyvar/queueing/celery_worker.py
Deserializes VariationRequest dicts, calls _register_variations() via the worker's AnyVar instance, and returns serialized RegisterVariationResponse dicts. Uses the same enter_task()/exit_task()/maybe_teardown_anyvar_app() lifecycle as existing VCF tasks.

New: has_variations_queueing_enabled() in src/anyvar/anyvar.py
A lighter prerequisite check than the VCF equivalent — requires only celery + CELERY_BROKER_URL (no aiofiles or ANYVAR_VCF_ASYNC_WORK_DIR), since variation registration doesn't involve file I/O.

Configuration

New environment variables (documented in docs/source/configuration/async.rst):

Variable Default Purpose
ANYVAR_VARIATIONS_ASYNC_FAILURE_STATUS_CODE 500 HTTP status returned by GET /variations/{run_id} on task failure
ANYVAR_EXPECTED_VARIATIONS_PER_SECOND 100 Used to estimate Retry-After header value

Async variation registration requires only CELERY_BROKER_URL and CELERY_BACKEND_URL — not the VCF-specific ANYVAR_VCF_ASYNC_WORK_DIR.

Tests

  • tests/unit/restapi/test_async_utils.py — unit tests for all three shared helpers covering success, failure, timeout, cleanup, and edge cases
  • tests/unit/restapi/test_variations_router.py — endpoint tests for PUT /variations (async disabled, duplicate run_id, async success, custom run_id, sync fallback) and GET /variations/{run_id} (async disabled, delegation to resolver)

Documentation

  • docs/source/usage/rest_api.rst — new "Asynchronous Bulk Registration" section with usage examples
  • docs/source/configuration/async.rst — new "Variation Registration Settings" section; clarifying note that variation async doesn't require ANYVAR_VCF_ASYNC_WORK_DIR

Closes #473

@ehclark ehclark requested a review from a team as a code owner June 4, 2026 19:22

@jennifer-bowser jennifer-bowser left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, this looks great! Just a couple of comments for you

Comment thread src/anyvar/restapi/async_utils.py Outdated
Comment thread src/anyvar/anyvar.py
@ehclark ehclark requested a review from jennifer-bowser June 11, 2026 17:12
@ehclark

ehclark commented Jun 19, 2026

Copy link
Copy Markdown
Contributor Author

@jennifer-bowser This is ready for re-review

@ehclark ehclark merged commit e901965 into main Jun 24, 2026
23 checks passed
@ehclark ehclark deleted the variations-high-perf branch June 24, 2026 18:59
theferrit32 added a commit that referenced this pull request Jun 24, 2026
Resolve conflicts from #480, which moved bulk-registration logic from
variations_router.py into the shared translate/register.py module.

- anyvar.py: keep both sides (projection helpers + main's queueing/error additions)
- variations_router.py: drop locally-defined registration funcs, import them from
  translate.register; keep `import os`
- translate/register.py: port the projection hook and add_projection_mappings onto
  main's relocated register_variations (also covers the Celery async path)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add async request-response (queueing) for PUT /variations endpoint

4 participants