feat(v1.1.5): pubsub::publish_durable SDK + pubsub:* triggers
Durable pub/sub through the universal outbox — the sixth trigger kind. - `pubsub::publish_durable(topic, message)` Rhai SDK (no handle; topics ARE the grouping unit). Message JSON-encoded; Blobs base64 at any depth. - `PubsubService` trait in picloud-shared with the topic matcher + validator (exact / `<prefix>.*` / `*`; mid-pattern wildcards rejected). `PostgresPubsubRepo` + `PubsubServiceImpl` in manager-core. - Publish-time fan-out: one outbox row per matching enabled pubsub trigger, all in ONE transaction (no half-fan-out on crash). No matching trigger → publish succeeds silently, zero rows. - `pubsub:*` trigger kind via Layout-E (0020: widen both CHECKs + pubsub_trigger_details + partial index), TriggerEvent::Pubsub + ctx.event.pubsub, dispatcher arm, admin endpoint POST /triggers/pubsub (validates topic pattern + reuses validate_trigger_target). - AppPubsubPublish capability → script:write (seven-scope held). - Dashboard Pub/Sub trigger form on the Triggers tab + list rendering. publish_ephemeral stays deferred to v1.2. ~18 new tests (service in-memory incl. transactional-rollback, shared matcher, bridge encoding). No DB required for the suite. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -22,9 +22,9 @@ use picloud_manager_core::{
|
||||
PostgresApiKeyRepository, PostgresAppDomainRepository, PostgresAppMembersRepository,
|
||||
PostgresAppRepository, PostgresDeadLetterRepo, PostgresDeadLetterService, PostgresDocsRepo,
|
||||
PostgresExecutionLogRepository, PostgresExecutionLogSink, PostgresKvRepo, PostgresOutboxRepo,
|
||||
PostgresRouteRepository, PostgresScriptRepository, PostgresTriggerRepo, PrincipalResolver,
|
||||
RepoResolver, RouteAdminState, RouteRepository, SandboxCeiling, ScriptRepository,
|
||||
TriggerConfig, TriggerRepo, TriggersState,
|
||||
PostgresPubsubRepo, PostgresRouteRepository, PostgresScriptRepository, PostgresTriggerRepo,
|
||||
PrincipalResolver, PubsubServiceImpl, RepoResolver, RouteAdminState, RouteRepository,
|
||||
SandboxCeiling, ScriptRepository, TriggerConfig, TriggerRepo, TriggersState,
|
||||
};
|
||||
use picloud_orchestrator_core::routing::{AppDomainTable, RouteTable};
|
||||
use picloud_orchestrator_core::{
|
||||
@@ -33,8 +33,8 @@ use picloud_orchestrator_core::{
|
||||
};
|
||||
use picloud_shared::{
|
||||
DeadLetterService, DocsService, ExecutionLogSink, FilesService, HttpService, InboxResolver,
|
||||
KvService, OutboxWriter, ScriptValidator, ServiceEventEmitter, Services, API_VERSION,
|
||||
PRODUCT_VERSION, SDK_VERSION, WIRE_VERSION,
|
||||
KvService, OutboxWriter, PubsubService, ScriptValidator, ServiceEventEmitter, Services,
|
||||
API_VERSION, PRODUCT_VERSION, SDK_VERSION, WIRE_VERSION,
|
||||
};
|
||||
use sqlx::postgres::PgPoolOptions;
|
||||
use sqlx::PgPool;
|
||||
@@ -169,7 +169,22 @@ pub async fn build_app(pool: PgPool, auth: AuthDeps) -> anyhow::Result<Router> {
|
||||
events.clone(),
|
||||
files_max_size,
|
||||
));
|
||||
let services = Services::new(kv, docs, dl_service.clone(), events, modules, http, files);
|
||||
// v1.1.5 durable pub/sub. Publishes fan out to matching pubsub
|
||||
// triggers at publish time (one outbox row each), delivered by the
|
||||
// same dispatcher as every other async trigger.
|
||||
let pubsub_repo = Arc::new(PostgresPubsubRepo::new(pool.clone()));
|
||||
let pubsub: Arc<dyn PubsubService> =
|
||||
Arc::new(PubsubServiceImpl::new(pubsub_repo, authz.clone()));
|
||||
let services = Services::new(
|
||||
kv,
|
||||
docs,
|
||||
dl_service.clone(),
|
||||
events,
|
||||
modules,
|
||||
http,
|
||||
files,
|
||||
pubsub,
|
||||
);
|
||||
let engine = Arc::new(Engine::new(Limits::default(), services));
|
||||
|
||||
// Compile the routes table once at startup; admin writes refresh it.
|
||||
|
||||
Reference in New Issue
Block a user