Skip to main content
Version: 8.10 (unreleased)

Eventual Consistency

Some Camunda endpoints — particularly search and "get by key" operations — are eventually consistent: data written via one API call may not be immediately visible to a follow-up read. Endpoints flagged as eventually consistent in the OpenAPI spec accept an optional consistency parameter that transparently polls until the data is visible (or a timeout is reached).

The consistency parameter is fully optional and defaults to None, so existing call sites continue to work unchanged.

from camunda_orchestration_sdk import CamundaClient
from camunda_orchestration_sdk.models import (
ProcessInstanceSearchQuery,
ProcessInstanceSearchQueryFilter,
)
from camunda_orchestration_sdk.runtime.eventual import (
ConsistencyOptions,
EventualConsistencyTimeoutError,
)

with CamundaClient() as client:
try:
result = client.search_process_instances(
data=ProcessInstanceSearchQuery(
filter_=ProcessInstanceSearchQueryFilter(
process_definition_id="order-process",
),
),
# Opt in to transparent polling. Default predicate accepts the
# first response whose `items` list is non-empty.
consistency=ConsistencyOptions(
wait_up_to_ms=5000,
poll_interval_ms=200,
),
)
for instance in result.items:
print(instance.process_instance_key)
except EventualConsistencyTimeoutError as exc:
print(f"Timed out after {exc.elapsed_ms}ms ({exc.attempts} attempts)")

For non-GET endpoints (search/list) the default predicate succeeds on the first response whose items list is non-empty. For GET endpoints it succeeds on any non-None result and transparently retries 404 Not Found while waiting. Pass a custom predicate to wait for a more specific condition:

from camunda_orchestration_sdk import CamundaClient
from camunda_orchestration_sdk.models import (
ProcessInstanceSearchQuery,
ProcessInstanceSearchQueryFilter,
)
from camunda_orchestration_sdk.runtime.eventual import ConsistencyOptions

with CamundaClient() as client:
# Wait until at least 3 instances are visible.
result = client.search_process_instances(
data=ProcessInstanceSearchQuery(
filter_=ProcessInstanceSearchQueryFilter(
process_definition_id="order-process",
),
),
consistency=ConsistencyOptions(
wait_up_to_ms=10_000,
poll_interval_ms=250,
predicate=lambda r: len(r.items) >= 3,
),
)
print(f"Got {len(result.items)} instances")

ConsistencyOptions fields:

FieldTypeDefaultDescription
wait_up_to_msintrequiredMaximum time to wait. 0 skips polling entirely.
poll_interval_msint500Delay between polling attempts (minimum 10ms).
predicateCallable[[T], bool] | NoneNoneCustom success check. Defaults as described above.

Polling aborts immediately on 400, 401, 403, 409, 422, and 5xx responses. 429 responses are retried with backoff. On timeout the SDK raises EventualConsistencyTimeoutError, which exposes attempts, elapsed_ms, last_status, and operation_id.

The same parameter is available on CamundaAsyncClient and behaves identically using asyncio.sleep for the polling delay.