To ensure that both Service B and Service C receive all messages from Service A, we create separate subscriptions to the same topic. Each subscription acts as an independent channel, allowing each service to process messages at its own pace.
from google.cloud import pubsub_v1
# Initialize the subscriber client
subscriber = pubsub_v1.SubscriberClient()
# Define subscription paths
subscription_b_id = "service-b-sub"
subscription_c_id = "service-c-sub"
subscription_b_path = subscriber.subscription_path(project_id, subscription_b_id)
subscription_c_path = subscriber.subscription_path(project_id, subscription_c_id)
# Create subscriptions (if they don't exist)
for subscription_path in [subscription_b_path, subscription_c_path]:
try:
subscriber.create_subscription(
request={"name": subscription_path, "topic": topic_path}
)
print(f"Subscription created: {subscription_path}")
except Exception:
print(f"Subscription already exists: {subscription_path}")
print("Both subscriptions are ready to receive messages!")
# Example: Pull messages for Service B
response = subscriber.pull(
request={
"subscription": subscription_b_path,
"max_messages": 10,
}
)
print(f"Pulled {len(response.received_messages)} messages for Service B:")
for received_message in response.received_messages:
message = received_message.message
print(f"Message ID: {message.message_id}")
print(f"Data: {message.data.decode('utf-8')}")
print(f"Attributes: {dict(message.attributes)}")
print(f"Publish time: {message.publish_time}")
print("---")
# Acknowledge the message
subscriber.acknowledge(
request={
"subscription": subscription_b_path,
"ack_ids": [received_message.ack_id],
}
)
print("All messages acknowledged for Service B")
# Example: Pull messages for Service C to demonstrate fan-out
response_c = subscriber.pull(
request={
"subscription": subscription_c_path,
"max_messages": 10,
}
)
print(f"\nPulled {len(response_c.received_messages)} messages for Service C:")
for received_message in response_c.received_messages:
message = received_message.message
print(f"Message ID: {message.message_id}")
print(f"Data: {message.data.decode('utf-8')}")
print(f"Attributes: {dict(message.attributes)}")
print("---")
# Acknowledge the message
subscriber.acknowledge(
request={
"subscription": subscription_c_path,
"ack_ids": [received_message.ack_id],
}
)
print("All messages acknowledged for Service C")
Output:
Subscription created: projects/your-gcp-project-id/subscriptions/service-b-sub
Subscription created: projects/your-gcp-project-id/subscriptions/service-c-sub
Both subscriptions are ready to receive messages!
Pulled 2 messages for Service B:
Message ID: 8234567890123456789
Data: Updates for Services B and C
Attributes: {}
Publish time: 2024-01-15 10:30:45.123456+00:00
---
Message ID: 8234567890123456790
Data: News update
Attributes: {'priority': 'high', 'department': 'IT'}
Publish time: 2024-01-15 10:30:46.789012+00:00
---
All messages acknowledged for Service B
Pulled 2 messages for Service C:
Message ID: 8234567890123456789
Data: Updates for Services B and C
Attributes: {}
Publish time: 2024-01-15 10:30:45.123456+00:00
---
Message ID: 8234567890123456790
Data: News update
Attributes: {'priority': 'high', 'department': 'IT'}
Publish time: 2024-01-15 10:30:46.789012+00:00
---
All messages acknowledged for Service C
By creating multiple subscriptions to the same topic, each service receives its own copy of every message. This approach demonstrates the fan-out pattern, ensuring reliable and independent message delivery to all subscribers. Notice how both Service B and Service C received the same messages with identical message IDs, confirming that the fan-out pattern is working correctly.