{"title":"PubSub Adapters","description":"Implement and register Amber V2 pub/sub adapters for WebSocket broadcasts","section":"guides/adapters","version":"v2","path":"guides/adapters/pubsub","canonical_url":"https://amberframework.org/docs/v2/guides/adapters/pubsub","markdown_url":"https://amberframework.org/docs/v2/guides/adapters/pubsub.md","inherited":false,"content_markdown":"# PubSub Adapters\n\nPub/sub adapters carry WebSocket messages between publishers and subscribers.\nAmber V2 includes `MemoryPubSubAdapter`; applications can register a shared\nbroker when broadcasts must cross process or host boundaries.\n\n## Complete adapter contract\n\nA custom adapter inherits `Amber::Adapters::PubSubAdapter`.\n\n**Reference API: implemented by a class under `src/adapters/`, for example\n`src/adapters/redis_pubsub_adapter.cr`. Do not copy the abstract class into the\napplication.**\n\n```crystal\nabstract class Amber::Adapters::PubSubAdapter\n  abstract def publish(topic : String, sender_id : String, message : JSON::Any) : Nil\n  abstract def subscribe(topic : String, &block : (String, JSON::Any) -> Nil) : Nil\n  abstract def unsubscribe(topic : String) : Nil\n  abstract def unsubscribe_all : Nil\n  abstract def close : Nil\nend\n```\n\nAdapters may also override `healthy?`, `subscriber_count`, and `active_topics`\nwhen the backend can report those values accurately.\n\nThe adapter owns broker subscriptions and resource cleanup. Calling\n`unsubscribe(topic)` must stop delivery for that topic; `unsubscribe_all` and\n`close` must release all remaining subscriptions and connections.\n\n## Built-in memory adapter\n\n**File: the applicable file under `config/environments/`, such as\n`config/environments/development.yml` — edit its existing `pubsub:` section.**\n\n```yaml\npubsub:\n  adapter: \"memory\"\n```\n\nUse it for development, tests, and intentional single-process deployments. A\nbrowser connected to one process cannot receive a message published only inside\nanother process through the memory adapter.\n\n## Register a shared adapter\n\n**File: `config/application.cr` — keep `require \"amber\"`, require the adapter\nclass, then register it before routes are loaded.**\n\n```crystal\n# config/application.cr\nrequire \"amber\"\nrequire \"../src/adapters/redis_pubsub_adapter\"\n\nAmber::Adapters::AdapterFactory.register_pubsub_adapter(\"redis\") do\n  RedisPubSubAdapter.new(redis_client)\nend\n```\n\n**File: `config/environments/production.yml` — edit the existing `pubsub:`\nsection after the adapter is registered.**\n\n```yaml\n# config/environments/production.yml\npubsub:\n  adapter: \"redis\"\n```\n\nRedis is an example of an application-supplied broker, not a built-in Amber V2\nadapter. The adapter must match the chosen Redis shard API, connection model,\nauthentication, TLS, and reconnect behavior.\n\n## Message contract\n\n`publish` receives a topic, sender ID, and `JSON::Any` message. A shared adapter\nmust preserve those three values across serialization so each subscriber callback\nreceives the original sender ID and message.\n\nDefine a collision-safe broker namespace for the application and environment.\nDo not subscribe directly to an untrusted topic name without validating or\nencoding it for the broker.\n\n## Adapter verification\n\n- publish and receive representative JSON values without losing types;\n- preserve the sender ID used to identify or filter an originating socket;\n- deliver to multiple subscribers on the same topic;\n- stop delivery after `unsubscribe` and `unsubscribe_all`;\n- close broker connections and listener fibers cleanly;\n- recover or fail visibly after a broker disconnect;\n- use two application processes to prove cross-process delivery;\n- verify topic isolation between environments and applications;\n- load-test the subscription count and message sizes expected in production.\n\nPresence, replay, persistence, ordering, and exactly-once delivery are not\nprovided merely by implementing the Amber pub/sub interface. If the application\nrequires one of those guarantees, specify and test it as part of the adapter.\n\nSee [Redis to Adapters](../../migration-guide/redis-to-adapters/) for a staged\ncutover and rollback checklist."}