GOOGLE CLOUD PUB/SUB → STACKIT RABBITMQ · GUIDE
Google Pub/Sub to STACKIT RabbitMQ
A Pub/Sub topic becomes an exchange on STACKIT RabbitMQ and each subscription becomes a queue bound to it. StackToIT writes the one RabbitMQ instance that hosts them all, and it names every delivery setting the draft does not carry: acknowledgement deadlines, retries, dead letters, push endpoints and ordering. This guide follows a five-resource estate through the run and then through the steps of the move.
Two topics, three subscriptions, assessed
A small estate written for this page and assessed by StackToIT on 4 November 2026: a topic with a pull subscription that has ordering, a retry policy and a dead-letter policy, a push subscription on the same topic, and a dead-letter topic with an inspection subscription of its own. Left: the input. Right: the one resource the engine wrote for all of it.
resource "google_pubsub_topic" "orders" {
name = "orders-created"
message_retention_duration = "86400s"
}
resource "google_pubsub_topic" "orders_dead" {
name = "orders-created-dead"
}
resource "google_pubsub_subscription" "billing" {
name = "billing-worker"
topic = google_pubsub_topic.orders.id
ack_deadline_seconds = 60
message_retention_duration = "604800s"
enable_message_ordering = true
retry_policy {
minimum_backoff = "10s"
maximum_backoff = "300s"
}
dead_letter_policy {
dead_letter_topic = google_pubsub_topic.orders_dead.id
max_delivery_attempts = 5
}
}
resource "google_pubsub_subscription" "webhook" {
name = "partner-webhook"
topic = google_pubsub_topic.orders.id
ack_deadline_seconds = 30
push_config {
push_endpoint = "https://partner.example.com/hooks/orders"
}
}
resource "google_pubsub_subscription" "dead_inspect" {
name = "dead-letter-inspect"
topic = google_pubsub_topic.orders_dead.id
ack_deadline_seconds = 20resource "stackit_rabbitmq_instance" "messaging" {
project_id = var.project_id
name = "messaging"
plan_name = var.rabbitmq_plan_name
version = var.rabbitmq_version
parameters = {
sgw_acl = join(",", var.rabbitmq_allowed_cidrs)
}
}Five resources, two units
The three subscriptions are not units of their own. They travel as facets of their topic, so the run counts 5 resources and 2 units, both classed REPLATFORM with MEDIUM confidence. The dead-letter topic sits in wave 1 and the main topic in wave 2, because the main topic depends on it.
One instance for every topic
The draft writes a single stackit_rabbitmq_instance for all migrated topics. Its access list is the variable rabbitmq_allowed_cidrs, which has no default and replaces STACKIT's default ranges, so you list the clients that really connect.
What the draft does not carry
The comment lines above the instance block in terraform/messaging.tf, one per topic and subscription, followed by the push and ordering warnings. They are the work list for the move: exchanges, queues and delivery rules are created in RabbitMQ by a person.
# NOT CARRIED (google_pubsub_topic.orders): message_retention_duration = 86400s, name = orders-created — the topic becomes an exchange and its subscriptions queues of the shared RabbitMQ instance, created in RabbitMQ by hand (not by this draft): names, delivery, retention and push settings are not generated.
# NOT CARRIED (google_pubsub_subscription.billing): ack_deadline_seconds = 60, dead_letter_policy, enable_message_ordering = true, message_retention_duration = 604800s, name = billing-worker, retry_policy — the topic becomes an exchange and its subscriptions queues of the shared RabbitMQ instance, created in RabbitMQ by hand (not by this draft): names, delivery, retention and push settings are not generated.
# NOT CARRIED (google_pubsub_subscription.webhook): ack_deadline_seconds = 30, name = partner-webhook, push_config — the topic becomes an exchange and its subscriptions queues of the shared RabbitMQ instance, created in RabbitMQ by hand (not by this draft): names, delivery, retention and push settings are not generated.
# NOT CARRIED (google_pubsub_topic.orders_dead): name = orders-created-dead — the topic becomes an exchange and its subscriptions queues of the shared RabbitMQ instance, created in RabbitMQ by hand (not by this draft): names, delivery, retention and push settings are not generated.
# NOT CARRIED (google_pubsub_subscription.dead_inspect): ack_deadline_seconds = 20, name = dead-letter-inspect — the topic becomes an exchange and its subscriptions queues of the shared RabbitMQ instance, created in RabbitMQ by hand (not by this draft): names, delivery, retention and push settings are not generated.
# google_pubsub_topic.orders: WARNING pubsub-push: Push subscriptions call HTTP endpoints; RabbitMQ delivers to consumers, so a small forwarding consumer (or the endpoint as consumer) replaces push.
# google_pubsub_topic.orders: WARNING pubsub-ordering: Ordered or exactly-once delivery is enabled; RabbitMQ orders per queue and delivers at least once, so consumers must be idempotent.How Pub/Sub concepts map to RabbitMQ
| Pub/Sub | STACKIT RabbitMQ | What the run says |
|---|---|---|
| Topic | Exchange on the shared instance | REPLATFORM; the topic name is a setting you confirm against publishers |
| Pull subscription | Queue bound to the exchange | REPLATFORM; clients switch from the Pub/Sub client to AMQP |
| Push subscription | A small forwarding consumer, or the endpoint itself as consumer | Warning in the draft: RabbitMQ delivers to consumers, it does not call HTTP endpoints |
| Acknowledgement deadline (10 to 600 seconds on Pub/Sub) | Consumer acknowledgements; the nearest service parameter is consumer_timeout | Open setting: you decide whether the workload depends on the deadline |
| Dead-letter topic and maximum delivery attempts | Dead-letter exchange; a delivery limit on quorum queues | Open setting: attempts, expiry and dead-letter targets become queue arguments you write |
| Retry policy with backoff | No counterpart; backoff lives in the consumer or in a delay design | Open setting: the run notes that STACKIT has no retry service |
| Message ordering | Order per queue, at-least-once delivery | Warning in the draft: RabbitMQ orders per queue, so consumers must be idempotent |
| Retention and replay | Queues keep messages until they are consumed | Open setting: decide whether anyone replays acknowledged messages |
The Pub/Sub ranges come from Google's subscription properties page; the run states the target side. Pub/Sub retains messages for up to 31 days, so a team that replays messages needs a design of its own on RabbitMQ.
The steps of the move, in order
1. Inventory the topics and who talks to them
Run the assessment on the Terraform that creates your topics and subscriptions. Topics created by hand or by another tool are not in the source and are not seen, so compare the result with the topics your project actually lists.
2. Set up the dead-letter side first
technical-sequencing.md in the migration folder puts the dead-letter topic in wave 1 and the topic that depends on it in wave 2. Build the same order on RabbitMQ: the dead-letter target must exist before a queue points at it.
3. Provision the instance and close its access list
Set the plan, the version and rabbitmq_allowed_cidrs, three of the variables the run leaves for you. STACKIT's own documentation recommends reviewing the default access list after creation and limiting it to the addresses your applications use.
4. Declare exchanges, queues and bindings
The draft does not generate them. For each subscription declare a queue and bind it. For dead letters RabbitMQ documents a policy key, dead-letter-exchange, and an argument, x-dead-letter-exchange; it advises the policy, because arguments cannot change without redeploying applications.
5. Translate the delivery rules
Map the acknowledgement deadline to consumer acknowledgements and maximum delivery attempts to a delivery limit. On quorum queues RabbitMQ dead-letters a message that comes back more often than that limit, with the reason delivery_limit. Write backoff into the consumer.
6. Replace push and make consumers idempotent
Put a forwarding consumer where a push endpoint was. Pub/Sub delivers at least once by default and RabbitMQ does too, so a consumer that handled duplicates before still has to.
7. Switch publishers, then consumers, and drain
The data-movement file of this run reads NOT APPLICABLE: a topic service is not listed as stateful, so messages in flight are not tracked. Drain the old subscriptions yourself before you retire them (general practice).
Decisions the architect owns
Queue type
Classic or quorum queues change how a delivery limit and dead lettering behave. The run does not choose.
One instance or several
The draft hosts every topic on one instance. Separate instances per environment or per team are your call.
Plan size
rabbitmq_plan_name has no default. The source states no message rate, so nothing in the run sizes it.
Replay
Decide whether acknowledged messages must stay readable, and for how long.
Cutover method
Publish to both systems for a while, or stop and switch. The run performs no cutover and gives no time estimate.
Questions teams ask
Does StackToIT create the exchanges and queues?
No. The draft writes the RabbitMQ instance. Exchanges, queues, bindings and delivery rules are created in RabbitMQ by a person, and the draft lists each setting it did not carry.
Can the applications keep the Pub/Sub client library?
No. Publishers and subscribers switch from the Pub/Sub client to AMQP, which is why the class is REPLATFORM and not a plain reconfiguration.
What replaces a push subscription?
A small consumer that receives from the queue and calls the endpoint, or the endpoint turned into a consumer. The draft raises this as a warning on the topic that owns the push subscription.
Are messages that are still queued moved for us?
No tool in this run moves messages. Drain the Pub/Sub subscriptions to zero, or accept dual publishing for a period, before the old topics are removed. Both are general practice, not run output.
Sources
Your next move: STACKIT.
Tell us about your estate. We show you what StackToIT delivers for it: target architecture, Terraform artifacts and a structured migration plan.