A fast and durable Pub/Sub channel over Websockets. FastAPI + WebSockets + PubSub == ⚡ 💪 ❤️
MIT License
A fast and durable Pub/Sub channel over Websockets. The easiest way to create a live publish / subscribe multi-cast over the web.
Supports and tested on Python >= 3.7
As seen at PyCon IL 2021 and EuroPython 2021
pip install fastapi_websocket_pubsub
The classic pub/sub pattern made easily accessible and scalable over the web and across your cloud in realtime; while enjoying the benefits of FastAPI (e.g. dependency injection).
FastAPI + WebSockets + PubSub == ⚡💪 ❤️
Subscribe
# Callback to be called upon event being published on server
async def on_event(data):
print("We got an event! with data- ", data)
# Subscribe for the event
client.subscribe("my event", on_event)
Publish
app = FastAPI()
endpoint = PubSubEndpoint()
endpoint.register_route(app, path="/pubsub")
endpoint.publish(["my_event_topic"], data=["my", "data", 1])
async with PubSubClient(server_uri="ws://localhost/pubsub") as client:
endpoint.publish(["my_event_topic"], data=["my", "data", 1])
app = FastAPI()
endpoint = PubSubEndpoint(broadcaster="postgres://localhost:5432/")
@app.websocket("/pubsub")
async def websocket_rpc_endpoint(websocket: WebSocket):
await endpoint.main_loop(websocket)
see examples/pubsub_broadcaster_server_example.py for full usage exampleIn the code below, a client connects to the server and subscribes to a topic named "triggered". Aside from PubSub websocket, the server also exposes a regular http route, which triggers publication of the event.
import asyncio
import uvicorn
from fastapi import FastAPI
from fastapi.routing import APIRouter
from fastapi_websocket_pubsub import PubSubEndpoint
app = FastAPI()
# Init endpoint
endpoint = PubSubEndpoint()
# register the endpoint on the app
endpoint.register_route(app, "/pubsub")
# Register a regular HTTP route
@app.get("/trigger")
async def trigger_events():
# Upon request trigger an event
endpoint.publish(["triggered"])
from fastapi_websocket_pubsub import PubSubClient
# Callback to be called upon event being published on server
async def on_trigger(data):
print("Trigger URL was accessed")
async with PubSubClient(server_uri="ws://localhost/pubsub") as client:
# Subscribe for the event
client.subscribe("triggered", on_trigger)
The combination of Websockets, and bi-directional Pub/Sub is ideal to create realtime data propagation solution at scale over the web.
Based on fastapi-websocket-rpc for a robust realtime bidirectional channel
Based on broadcaster for syncing server instances
Server Endpoint:
Based on FastAPI: enjoy all the benefits of a full ASGI platform, including Async-io and dependency injections (for example to authenticate connections)
Based on Pydantic: easily serialize structured data as part of RPC requests and responses. Simply Pass Pydantic data models as PubSub published data to have it available as part of an event.
Client :
Based on Tenacity: allowing configurable retries to keep to connection alive
Based on python websockets - a more comprehensive client than the one offered by FastAPI
fastapi-websocket-pubsub uses fastapi-websocket-rpc for logging config.
It provides a helper logging module to control how it produces logs for you.
See fastapi_websocket_rpc/logger.py.
Use logging_config.set_mode
or the 'WS_RPC_LOGGING' environment variable to choose the logging method you prefer.
Or override completely via default logging config (e.g. 'logging.config.dictConfig'), all logger name start with: 'fastapi.ws_rpc.pubsub'
example:
# set RPC to log like UVICORN
from fastapi_websocket_rpc.logger import logging_config, LoggingModes
logging_config.set_mode(LoggingModes.UVICORN)