Hash-Partitioned AttributeMap
Use this pattern when records have a stable lookup key and each record contains structured data. The sample stores customer profiles by email address without loading the entire directory.
CustomerDirectoryFlow is an RPC-only Flow. Start it once with no Flow timeout. CustomerProfilesByEmailPartition has 1,000 logical instances, created only when needed. Each instance stores a dictionary from canonical email to the full profile.
Stable partition algorithm
Every SDK uses the same algorithm:
- Require a non-empty ASCII email address.
- Remove leading and trailing ASCII whitespace.
- Lowercase ASCII letters from A through Z.
- Calculate 32-bit FNV-1a over the canonical email bytes with wrapping overflow.
- Select hash modulo 1000 and format the instance from partition-000 through partition-999.
A hash collision only places multiple emails in one partition. The dictionary still distinguishes records by their complete canonical email.
Exact lookup and serialized writes
The adapter and handler both calculate the partition. UpsertCustomerProfile adds an exact load and an instance lock for the same partition. The handler recalculates it, reads the bucket, updates one profile, and writes the bucket back. Writes to one partition serialize. Writes to different partitions can run concurrently.
Lock acquisition does not queue callers. Concurrent writes to one partition can receive an RPCLockConflict. Retry the idempotent upsert with application-appropriate backoff. Successful writes remain serialized and preserve every record in the bucket.
GetCustomerProfileByEmail loads one partition without a write lock. A missing partition and a missing canonical email both return not found.
saved_profile = await app_state.client.invoke_rpc(
flow.upsert_customer_profile,
FLOW_ID,
profile,
options=RPCInvokeOptions(
lock_attribute_map_instances=(
flow.customer_profiles_by_email_partition.lock(partition_name),
),
load_attribute_map_instances=(
flow.customer_profiles_by_email_partition.load(partition_name),
),
),
)
Example: examples/python/dex_examples/patterns/hash-partitioned-attribute-map/controller.py
All writers must use the same instance-lock rule. Dex locks are cooperative; a writer that omits the lock can still race with conforming writers.
HTTP API
POST /patterns/hash-partitioned-attribute-map/start
PUT /patterns/hash-partitioned-attribute-map/customer-profile
GET /patterns/hash-partitioned-attribute-map/customer-profile?emailAddress=alice@example.com
The partition count is persisted schema. Changing it moves most keys and requires a complete rehash or a new Flow version. This sample intentionally omits deletion, full-directory enumeration, cross-field search, and partition resizing.
Run the HTTP example from the examples playground.