Skip to content

feat(pubsub): named-broker and broker-per-tenant support (GH-3306)#3318

Merged
jeremydmiller merged 1 commit into
mainfrom
feat/pubsub-named-and-tenant-3306
Jul 6, 2026
Merged

feat(pubsub): named-broker and broker-per-tenant support (GH-3306)#3318
jeremydmiller merged 1 commit into
mainfrom
feat/pubsub-named-and-tenant-3306

Conversation

@jeremydmiller

Copy link
Copy Markdown
Member

Closes #3306

Brings the GCP Pub/Sub transport (Wolverine.Pubsub) up to parity with the other transports on the two established multi-broker features. It had neither before.

Feature 1 — Named broker

  • PubsubTransport(string) now sets the transport Protocol (broker name / URI scheme) instead of ProjectId, so TransportCollection.GetOrCreate<T>(name) can spin up named brokers via Activator.CreateInstance(typeof(PubsubTransport), name.Name). ProjectId is set separately by UsePubsub/AddNamedPubsubBroker. ResourceUri now derives from Protocol, so a named broker's endpoints get scheme {brokerName}://{projectId}/{topic}.
  • New API: AddNamedPubsubBroker(BrokerName, projectId, …), ListenToPubsubTopicOnNamedBroker, ToPubsubTopicOnNamedBroker (mirrors SQS/Kafka).
  • Mechanical cost: the ~25 test call sites of new PubsubTransport("wolverine") were updated to the object initializer new PubsubTransport { ProjectId = "wolverine" }.

Feature 2 — Broker-per-tenant (project-id-per-tenant, modeled after NATS)

  • New PubsubTenant + PubsubClientSet: each tenant builds its own PublisherServiceApiClient/SubscriberServiceApiClient pair in ConnectAsync, seeded from the parent's credential/emulator hooks (a tenant only re-points the axes it overrides).
  • Senders/listeners (which previously hard-read _transport.PublisherApiClient/SubscriberApiClient) are parameterized with a PubsubClientSet, so one endpoint per topic can publish/consume over a different GCP project at runtime, keyed by Envelope.TenantId — the same "swap the client" model NATS uses for its connection.
  • CreateSenderTenantedSender with fire-and-forget InlinePubsubSender for the default fallback and every tenant (never BatchedSender, per the Message is stuck in outbox with multiple tenants and durable messaging #2361 outbox-deletion regression).
  • BuildListenerAsyncCompoundListener with a per-tenant listener wrapped in ReceiverWithRules([new TenantIdRule(tenant.TenantId)]). Pub/Sub acks inline in the streaming callback, so per-envelope completion never routes back through the compound listener.
  • SetupAsync provisions the topic (+ subscription for listeners) under each tenant project, applying the per-node competing-consumer subscription naming once so all projects share the same subscription id.
  • New API: PubsubConfiguration.TenantIdBehavior(TenantedIdBehavior), AddTenant(tenantId, projectId), AddTenant(tenantId, projectId, Action<PubsubTenant>).

GCP-specific note

Project-id-per-tenant is the natural isolation axis: TopicName/SubscriptionName embed the project id, so the same logical topic under a different project is already a physically distinct GCP resource — "shared by name, isolated by project". Topology is not fragmented per tenant.

Tests

Full Wolverine.Pubsub.Tests green: 178 passed, 0 failed, 0 skipped (against the emulator). New coverage:

  • Named broker (CI-safe): distinct Protocol+ProjectId, endpoint URI scheme == broker name. Integration: round-trips a message published/listened exclusively via ...OnNamedBroker on a second project (wolverine2) on the same emulator.
  • Per-tenant (CI-safe config tests + integration): tenant message → project wolverine2 and not wolverine; default message → wolverine; inbound message stamped with its TenantId; auto-provision under the tenant project; TenantIdBehavior variants. Integration tests skip-guard when the emulator/Docker is unavailable.

Build gate

dotnet build wolverine.slnx -c Release0 errors, 0 warnings.

Docs

Added "Multiple / Named Brokers" and "Multi-Tenancy with a Broker Per Tenant" sections to docs/guide/messaging/transports/gcp-pubsub/index.md with compiling snippets in DocumentationSamples.cs.

🤖 Generated with Claude Code

Bring the GCP Pub/Sub transport up to parity with the other transports on
the two established multi-broker features.

Named broker:
- PubsubTransport(string) now sets the transport Protocol (broker name / URI
  scheme) instead of ProjectId, so TransportCollection.GetOrCreate<T>(name)
  can spin up named brokers via Activator.CreateInstance. ProjectId is set
  separately by UsePubsub/AddNamedPubsubBroker. ResourceUri derives from
  Protocol so named brokers get scheme {brokerName}://{projectId}/{topic}.
- New AddNamedPubsubBroker + ListenToPubsubTopicOnNamedBroker +
  ToPubsubTopicOnNamedBroker.

Broker-per-tenant (project-id-per-tenant, modeled after NATS):
- New PubsubTenant + PubsubClientSet; each tenant builds its own
  Publisher/Subscriber client pair in ConnectAsync, seeded from the parent's
  credential/emulator hooks. Senders/listeners are parameterized with a
  PubsubClientSet so one endpoint per topic can publish/consume over a
  different GCP project at runtime, keyed by Envelope.TenantId.
- CreateSender -> TenantedSender with fire-and-forget InlinePubsubSender for
  the default fallback + every tenant (GH-2361). BuildListenerAsync ->
  CompoundListener with a per-tenant listener wrapped in
  ReceiverWithRules([TenantIdRule]). SetupAsync provisions the topology under
  each tenant project, preserving per-node subscription naming.
- New PubsubConfiguration.TenantIdBehavior + AddTenant overloads.

Updates the ~25 test call sites of new PubsubTransport("x") to the object
initializer new PubsubTransport { ProjectId = "x" }. Adds named-broker and
per-tenant unit + integration tests (skip-guarded on the emulator) and docs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@jeremydmiller
jeremydmiller marked this pull request as ready for review July 6, 2026 03:06
@jeremydmiller
jeremydmiller merged commit 1d87b2f into main Jul 6, 2026
25 checks passed
This was referenced Jul 9, 2026
This was referenced Jul 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

GCP Pub/Sub: add named-broker and broker-per-tenant support

1 participant