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:
@@ -21,12 +21,13 @@ use std::sync::Arc;
|
||||
|
||||
use crate::{
|
||||
DeadLetterService, DocsService, EmailService, FilesService, GroupDocsService,
|
||||
GroupFilesService, GroupKvService, GroupPubsubService, HttpService, InvokeService, KvService,
|
||||
ModuleSource, NoopDeadLetterService, NoopDocsService, NoopEmailService, NoopEventEmitter,
|
||||
NoopFilesService, NoopGroupDocsService, NoopGroupFilesService, NoopGroupKvService,
|
||||
NoopGroupPubsubService, NoopHttpService, NoopInvokeService, NoopKvService, NoopModuleSource,
|
||||
NoopPubsubService, NoopQueueService, NoopSecretsService, NoopUsersService, NoopVarsService,
|
||||
PubsubService, QueueService, SecretsService, ServiceEventEmitter, UsersService, VarsService,
|
||||
GroupFilesService, GroupKvService, GroupPubsubService, GroupQueueService, HttpService,
|
||||
InvokeService, KvService, ModuleSource, NoopDeadLetterService, NoopDocsService,
|
||||
NoopEmailService, NoopEventEmitter, NoopFilesService, NoopGroupDocsService,
|
||||
NoopGroupFilesService, NoopGroupKvService, NoopGroupPubsubService, NoopGroupQueueService,
|
||||
NoopHttpService, NoopInvokeService, NoopKvService, NoopModuleSource, NoopPubsubService,
|
||||
NoopQueueService, NoopSecretsService, NoopUsersService, NoopVarsService, PubsubService,
|
||||
QueueService, SecretsService, ServiceEventEmitter, UsersService, VarsService,
|
||||
};
|
||||
|
||||
/// SDK service bundle. See module docs for the lifecycle and the v1.1.x
|
||||
@@ -139,6 +140,12 @@ pub struct Services {
|
||||
/// `shared = true` group pubsub triggers. Wired via
|
||||
/// [`Services::with_group_pubsub`]; defaults to `NoopGroupPubsubService`.
|
||||
pub group_pubsub: Arc<dyn GroupPubsubService>,
|
||||
|
||||
/// Shared cross-app group QUEUES (§11.6 D3). Scripts get
|
||||
/// `queue::shared_collection(name)` — enqueue into a group-keyed store
|
||||
/// drained by competing per-descendant consumers. Wired via
|
||||
/// [`Services::with_group_queue`]; defaults to `NoopGroupQueueService`.
|
||||
pub group_queue: Arc<dyn GroupQueueService>,
|
||||
}
|
||||
|
||||
impl Services {
|
||||
@@ -185,6 +192,7 @@ impl Services {
|
||||
group_docs: Arc::new(NoopGroupDocsService),
|
||||
group_files: Arc::new(NoopGroupFilesService),
|
||||
group_pubsub: Arc::new(NoopGroupPubsubService),
|
||||
group_queue: Arc::new(NoopGroupQueueService),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -217,6 +225,13 @@ impl Services {
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the §11.6 D3 shared group-QUEUE service (picloud binary; tests leave noop).
|
||||
#[must_use]
|
||||
pub fn with_group_queue(mut self, group_queue: Arc<dyn GroupQueueService>) -> Self {
|
||||
self.group_queue = group_queue;
|
||||
self
|
||||
}
|
||||
|
||||
/// All-noop bundle for tests that build an `Engine` but don't
|
||||
/// exercise the stateful services. Returns the same shape as
|
||||
/// `Services::new` so callers can't accidentally rely on a stub
|
||||
|
||||
Reference in New Issue
Block a user