feat(shared-queues): group-keyed queue store + enqueue service + SDK (D3.1)
The producer side of shared durable queues:
- migration 0065 group_queue_messages (mirrors 0034, keyed by (group_id,
collection); CASCADE on group delete).
- GroupQueueRepo/PostgresGroupQueueRepo: enqueue + the competing-consumer
claim (FOR UPDATE SKIP LOCKED) + ack/nack/drop_exhausted/reclaim/depth.
- GroupQueueService trait (shared) + GroupQueueServiceImpl: resolve owning
group (kind='queue') from cx.app_id's chain, require editor+
(GroupQueueEnqueue, fails closed on anon), size-cap, enqueue.
- SDK: `queue::shared_collection("name")` -> GroupQueueHandle with
`.enqueue(msg[, opts])` / `.depth()` / `.depth_pending()`; wired through
Services + the picloud binary.
- authz: Capability::GroupQueueEnqueue(GroupId), editor+ / script:write.
Deterministic test proves competing consumers claim each message exactly
once. Consumption wiring (materialized consumers + dispatcher branch) lands
in D3.2.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -264,6 +264,19 @@ table: group_members
|
||||
role: text NOT NULL
|
||||
created_at: timestamp with time zone NOT NULL default=now()
|
||||
|
||||
table: group_queue_messages
|
||||
id: uuid NOT NULL default=gen_random_uuid()
|
||||
group_id: uuid NOT NULL
|
||||
collection: text NOT NULL
|
||||
payload: jsonb NOT NULL
|
||||
enqueued_at: timestamp with time zone NOT NULL default=now()
|
||||
deliver_after: timestamp with time zone NULL
|
||||
claim_token: uuid NULL
|
||||
claimed_at: timestamp with time zone NULL
|
||||
attempt: integer NOT NULL default=0
|
||||
max_attempts: integer NOT NULL default=3
|
||||
enqueued_by_principal: uuid NULL
|
||||
|
||||
table: groups
|
||||
id: uuid NOT NULL default=gen_random_uuid()
|
||||
parent_id: uuid NULL
|
||||
@@ -559,6 +572,12 @@ indexes on group_members:
|
||||
group_members_pkey: public.group_members USING btree (group_id, user_id)
|
||||
group_members_user_id_idx: public.group_members USING btree (user_id)
|
||||
|
||||
indexes on group_queue_messages:
|
||||
group_queue_messages_pkey: public.group_queue_messages USING btree (id)
|
||||
idx_group_queue_messages_claimed: public.group_queue_messages USING btree (claimed_at) WHERE (claim_token IS NOT NULL)
|
||||
idx_group_queue_messages_dispatch: public.group_queue_messages USING btree (group_id, collection, enqueued_at) WHERE (claim_token IS NULL)
|
||||
idx_group_queue_messages_group_collection: public.group_queue_messages USING btree (group_id, collection)
|
||||
|
||||
indexes on groups:
|
||||
groups_parent_id_idx: public.groups USING btree (parent_id)
|
||||
groups_pkey: public.groups USING btree (id)
|
||||
@@ -793,6 +812,10 @@ constraints on group_members:
|
||||
[FOREIGN KEY] group_members_user_id_fkey: FOREIGN KEY (user_id) REFERENCES admin_users(id) ON DELETE CASCADE
|
||||
[PRIMARY KEY] group_members_pkey: PRIMARY KEY (group_id, user_id)
|
||||
|
||||
constraints on group_queue_messages:
|
||||
[FOREIGN KEY] group_queue_messages_group_id_fkey: FOREIGN KEY (group_id) REFERENCES groups(id) ON DELETE CASCADE
|
||||
[PRIMARY KEY] group_queue_messages_pkey: PRIMARY KEY (id)
|
||||
|
||||
constraints on groups:
|
||||
[FOREIGN KEY] groups_parent_id_fkey: FOREIGN KEY (parent_id) REFERENCES groups(id) ON DELETE RESTRICT
|
||||
[PRIMARY KEY] groups_pkey: PRIMARY KEY (id)
|
||||
@@ -949,3 +972,4 @@ constraints on vars:
|
||||
0062: materialized triggers
|
||||
0063: materialized unique
|
||||
0064: shared topic queue kinds
|
||||
0065: group queues
|
||||
|
||||
Reference in New Issue
Block a user