Guides
Pub/Sub
NoBS supports a publish/subscribe (PubSub) pattern for event-driven workflows. PubSub allows one component of your system to publish an event and multiple subscribers to react to that event independently. This is useful for systems where an action should trigger one or more asynchronous side effects, such as sending notifications, recording analytics, or triggering downstream processing.
Defining an Event
An event must be represented as a typed request model. This ensures structured and validated messages.
from pydantic import BaseModel
class CreatedUser(BaseModel):
id: int
name: str
email: str
Next, define the PubSub topic:
from nobs.pubsub import PubSub
on_user_created = PubSub(CreatedUser, subject="on_user_created")
The subject is the channel or topic name. All subscribers connected to this subject will receive every event published to it.
Creating Subscribers
Subscribers are functions that accept the event model as an argument. These functions run when a message is published to the PubSub subject.
def send_verify_email(user: CreatedUser) -> None:
...
def predict_cluster(user: CreatedUser) -> None:
...
Each subscriber is registered on the project:
from nobs.models import Project, Compute
from nobs.secrets import BaseSettings, SecretStr
class SendGridConfig(BaseSettings):
api_token: SecretStr
project = Project(
name="my-project",
verify_email=on_user_created.subscriber(
send_verify_email,
secrets=[SendGridConfig]
),
predict_cluster=on_user_created.subscriber(
predict_cluster,
compute=Compute(
mvcpu_limit=1000,
mb_memory_limit=1024
)
)
)
Key points
send_verify_emailrequires a SendGrid API token, so it declares a secrets list.predict_clusterrequests additional CPU and memory resources, so it configures compute.
Publishing Events
To trigger the subscribers, publish an event:
await on_user_created.publish(
CreatedUser(
id=1,
name="Ash Ketchum",
email="ash@example.com",
)
)
All subscribers will receive and process this event independently. The caller does not wait for subscriber functions to complete.
When to Use PubSub
Use PubSub when:
- Multiple workflows should trigger from a single action
- You want to decouple producers from consumers
- Tasks should run asynchronously and independently of request/response cycles
Examples include:
- Sending welcome or verification emails
- Running analytics processing
- Kicking off model predictions or data enrichment pipelines
When to Use PubSub Instead of a Queue Worker
A queue worker is designed for one-to-one task execution. A message is produced, added to a queue, and one worker consumes it. This works well when each task is independent and produces a single result or side effect.
PubSub is designed for one-to-many event distribution. A published event can trigger several subscribers, each performing different actions. The producer does not need to know who will receive the event or what they will do with it.
Choose PubSub when:
- The action should trigger multiple workflows. For example, creating a user may send a welcome email, record analytics, and schedule background enrichment.
- You want strong decoupling between systems. The producer only emits a well-defined event and does not depend on downstream logic or services.
- New behavior may be added later without changing existing code. New subscribers can be added to the event subject without modifying the event producer.
Choose a queue worker when:
- The work is single-purpose and results in one job to be processed.
- You need strict ordering or single-task guarantees.
- The task should be retried or tracked as a single job rather than as part of a fan-out pattern.
In short, use PubSub when an event represents something that happened and other parts of the system should react independently. Use a queue worker when you need to schedule or manage a discrete background job with a single responsibility.