Async Caching Guide

Use this guide for exact behavior of async v2 wrappers, transport selection, and cache tuning options.

Where async wrappers live

  • Wrapper exports: src/britecore_sdk/api/api_calls/v2/__init__.py

  • Async transport: src/britecore_sdk/api/britecore_async_api_client.py

  • Cache primitives: src/britecore_sdk/api/request_cache.py

Transport modes

AsyncBritecoreAPIClient supports two transport backends via the async_transport constructor kwarg:

Mode

Value

Behavior

Extra required

Threaded (default)

"threaded"

Wraps sync urllib3 client in asyncio.to_thread

None

Native async

"httpx"

Uses httpx.AsyncClient for true non-blocking I/O

britecore_sdk[async-http]

Threaded transport (default)

No extra packages needed. Existing code continues to work without changes.

from britecore_sdk.api import AsyncBritecoreAPIClient

# default — threaded transport
client = AsyncBritecoreAPIClient(target_site="prod")

httpx native async transport

Install the optional extra first:

pip install britecore_sdk[async-http]
from britecore_sdk.api import AsyncBritecoreAPIClient

client = AsyncBritecoreAPIClient(target_site="prod", async_transport="httpx")

You can inject a pre-built httpx.AsyncClient for connection pool sharing or testing:

import httpx
from britecore_sdk.api import AsyncBritecoreAPIClient

shared_httpx = httpx.AsyncClient(timeout=30)
client = AsyncBritecoreAPIClient(
    target_site="prod",
    async_transport="httpx",
    httpx_client=shared_httpx,
)

Note: Dry-run requests always use the threaded transport even in httpx mode, since they do not actually send a network request.

Default behavior

Read wrappers in async v2 enable caching by default:

  • Quotes (aget_quote): namespace quotes, TTL 60 seconds

  • Contacts (aget_contact, afind_contact_by_params): namespace contacts, TTL 60 seconds

  • Policies (aretrieve_policy, aretrieve_policy_snapshot, etc.): namespace policies, TTL 60 seconds

Mutation wrappers invalidate related read namespaces on successful (HTTP 200) responses:

  • Quote mutations invalidate quotes

  • Contact mutations invalidate contacts

  • Policy mutations invalidate policies

Exact usage

import asyncio

from britecore_sdk.api.api_calls.v2 import (
    acreate_full_quote,
    aget_contact,
    aget_quote,
    aretrieve_policy,
)


async def main() -> None:
    # Cached read (first call live, second call cached).
    quote_1 = await aget_quote("quote_123")
    quote_2 = await aget_quote("quote_123")

    # Cached read with per-call TTL override.
    contact = await aget_contact("contact_123", cache_ttl_seconds=180)

    # Cached read with in-flight de-duplication enabled (default True).
    policy = await aretrieve_policy(
        policy_number="POL001",
        revision_state="active",
        dedupe_in_flight=True,
    )

    # Mutation invalidates quote namespace on success.
    _, created_quote_id = await acreate_full_quote({"quote": {"name": "Example"}})

    print(quote_1, quote_2, contact, policy, created_quote_id)


asyncio.run(main())

Cache controls (RequestParameters)

All async wrappers accept these optional kwargs:

  • cache_enabled: enable/disable caching for a call

  • cache_ttl_seconds: TTL override in seconds

  • cache_namespace: namespace label used by invalidation

  • cache_key_parts: additional deterministic cache key fragments

  • cache_bypass: force live request and skip cache read/write

  • cache_invalidate_on_success: namespaces to invalidate after successful mutation

  • dedupe_in_flight: deduplicate concurrent identical requests

  • dry_run: return a synthetic success payload without sending a live request

  • dry_run_include_sensitive_headers: include unredacted headers in dry-run output

Example overrides:

fresh_quote = await aget_quote("quote_123", cache_bypass=True)

policy = await aretrieve_policy(
    policy_id="uuid",
    cache_enabled=True,
    cache_ttl_seconds=300,
    cache_key_parts=["tenant:acme", "view:summary"],
)

Async dry-run behavior

Async clients support the same client-level dry-run default as the sync client:

import asyncio

from britecore_sdk.api.api_calls import init_async_api_client
from britecore_sdk.api.api_calls.v2.async_policies import aretrieve_policy


async def main() -> None:
    init_async_api_client(client_dry_run=True)
    preview = await aretrieve_policy(policy_number="POL001")
    print(preview["dry_run"])
    print(preview["auth_skipped"])


asyncio.run(main())

Notes:

  • Async dry-run requests bypass async cache reads/writes and in-flight dedupe.

  • For OAuth sites, async dry-run skips token acquisition unless you explicitly pass headers.

  • Per-call dry_run=False overrides an inherited client default.

  • Sensitive request-body fields are always redacted in dry-run output (for example api_key and token/secret/password-like keys), even when sensitive headers are included.

Manage cache manually

The module-level async client instance is shared and lazily initialized:

from britecore_sdk.api.api_calls import get_async_api_client

client = get_async_api_client()
removed = client.invalidate_cache_namespaces(["quotes", "contacts", "policies"])
client.clear_cache()
print(removed)

Notes

  • Authorization headers are excluded from cache key generation.

  • Cache writes happen only on successful (HTTP 200) responses.

  • cache_bypass=True also bypasses in-flight dedupe for that request.