Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 10 additions & 6 deletions docs/handler-authoring.md
Original file line number Diff line number Diff line change
Expand Up @@ -629,14 +629,18 @@ top-level `adcp.server`):

```python
from adcp.server.idempotency import PgBackend
idempotency = IdempotencyStore(backend=PgBackend(pool=pg_pool), ttl_seconds=86_400)
idempotency = IdempotencyStore(
backend=PgBackend(pool=pg_pool, lock_pool=idempotency_lock_pool),
ttl_seconds=86_400,
)
```

The Pg-backed store survives restarts and is shared across workers.
`PgBackend` commits the cached response atomically with your handler's
business write when both run inside the same transaction — no window
where the side effect lands
but the cache entry doesn't.
The Pg-backed store survives restarts and is shared across workers. Size the
dedicated `lock_pool` for the maximum number of concurrently executing unique
idempotent operations; cache-hit replays do not acquire it. The SDK commits
the cache entry while holding the per-key advisory lock, but it does not share
a transaction with unrelated handler business writes. Protect non-idempotent
business effects with a matching database uniqueness constraint.

**`caller_identity` + `tenant_id` must be populated.** The store keys
its cache on `(tenant_id, caller_identity, idempotency_key)`. If
Expand Down
13 changes: 12 additions & 1 deletion src/adcp/canonical_formats/references.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
DEFAULT_REFERENCE_TIMEOUT_SECONDS = 5.0
DEFAULT_REFERENCE_BODY_LIMIT_BYTES = 1024 * 1024
DEFAULT_MAX_SCHEMA_REFS = 256
DEFAULT_MAX_SCHEMA_IDS = 256
DEFAULT_MAX_REF_DEPTH = 8
DEFAULT_MAX_SCHEMA_KEYWORDS = 10_000
DEFAULT_MAX_SCHEMA_DEPTH = 128
Expand Down Expand Up @@ -157,6 +158,7 @@ def __init__(
timeout: float = DEFAULT_REFERENCE_TIMEOUT_SECONDS,
max_body_bytes: int = DEFAULT_REFERENCE_BODY_LIMIT_BYTES,
max_schema_refs: int = DEFAULT_MAX_SCHEMA_REFS,
max_schema_ids: int = DEFAULT_MAX_SCHEMA_IDS,
max_ref_depth: int = DEFAULT_MAX_REF_DEPTH,
max_schema_keywords: int = DEFAULT_MAX_SCHEMA_KEYWORDS,
max_schema_depth: int = DEFAULT_MAX_SCHEMA_DEPTH,
Expand All @@ -165,6 +167,7 @@ def __init__(
self._timeout = timeout
self._max_body_bytes = max_body_bytes
self._max_schema_refs = max_schema_refs
self._max_schema_ids = max_schema_ids
self._max_ref_depth = max_ref_depth
self._max_schema_keywords = max_schema_keywords
self._max_schema_depth = max_schema_depth
Expand Down Expand Up @@ -318,6 +321,7 @@ def _validate_schema(
document,
base_uri=reference.uri,
max_refs=self._max_schema_refs,
max_ids=self._max_schema_ids,
max_ref_depth=self._max_ref_depth,
max_keywords=self._max_schema_keywords,
max_depth=self._max_schema_depth,
Expand Down Expand Up @@ -534,11 +538,12 @@ def _validate_schema_refs(
*,
base_uri: str,
max_refs: int,
max_ids: int,
max_ref_depth: int,
max_keywords: int,
max_depth: int,
) -> str | None:
state = _SchemaRefState(max_refs=max_refs, max_keywords=max_keywords)
state = _SchemaRefState(max_refs=max_refs, max_ids=max_ids, max_keywords=max_keywords)
return _walk_schema_refs(
document,
base_uri=base_uri,
Expand All @@ -552,8 +557,10 @@ def _validate_schema_refs(
@dataclass
class _SchemaRefState:
max_refs: int
max_ids: int
max_keywords: int
refs: int = 0
ids: int = 0
keywords: int = 0


Expand All @@ -577,6 +584,9 @@ def _walk_schema_refs(
if raw_id is not None:
if not isinstance(raw_id, str):
return "$id must be a string"
state.ids += 1
if state.ids > state.max_ids:
return "format_schema exceeds $id count bound"
id_error, resolved_id = _validate_schema_id_value(raw_id, base_uri=base_uri)
if id_error is not None:
return id_error
Expand Down Expand Up @@ -709,6 +719,7 @@ def _trusted_aao_catalog_origin(parts: SplitResult) -> bool:
"CanonicalReferenceResolver",
"CanonicalReferenceResult",
"CanonicalReferenceStatus",
"DEFAULT_MAX_SCHEMA_IDS",
"DEFAULT_REFERENCE_BODY_LIMIT_BYTES",
"DEFAULT_REFERENCE_TIMEOUT_SECONDS",
"parse_canonical_reference",
Expand Down
Loading
Loading