{"id":33916742,"url":"https://github.com/daemonzone/redis-streams-pubsub","last_synced_at":"2025-12-12T07:29:46.957Z","repository":{"id":326890190,"uuid":"1107074441","full_name":"daemonzone/redis-streams-pubsub","owner":"daemonzone","description":"A simple, elegant Ruby gem that provides a publish/subscribe API on top of Redis Streams. It simplifies working with Redis Streams by offering familiar pub/sub patterns with automatic consumer group management and message acknowledgment","archived":false,"fork":false,"pushed_at":"2025-11-30T15:15:11.000Z","size":10,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-12-02T21:36:59.625Z","etag":null,"topics":["gem","pubsub","redis","redis-streams","ruby","ruby-on-rails","rubygems"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/daemonzone.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-11-30T14:30:37.000Z","updated_at":"2025-11-30T15:27:49.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/daemonzone/redis-streams-pubsub","commit_stats":null,"previous_names":["daemonzone/redis-streams-pubsub"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/daemonzone/redis-streams-pubsub","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/daemonzone%2Fredis-streams-pubsub","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/daemonzone%2Fredis-streams-pubsub/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/daemonzone%2Fredis-streams-pubsub/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/daemonzone%2Fredis-streams-pubsub/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/daemonzone","download_url":"https://codeload.github.com/daemonzone/redis-streams-pubsub/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/daemonzone%2Fredis-streams-pubsub/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":27502904,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-12-04T02:00:07.142Z","response_time":60,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["gem","pubsub","redis","redis-streams","ruby","ruby-on-rails","rubygems"],"created_at":"2025-12-12T07:29:46.249Z","updated_at":"2025-12-12T07:29:46.942Z","avatar_url":"https://github.com/daemonzone.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Redis Streams PubSub\n\nA simple, elegant Ruby gem that provides a publish/subscribe API on top of Redis Streams. It simplifies working with Redis Streams by offering familiar pub/sub patterns with automatic consumer group management and message acknowledgment.\n\n## Features\n\n- **Simple API**: Familiar publish/subscribe interface\n- **Consumer Groups**: Automatic consumer group creation and management\n- **Message Acknowledgment**: Automatic XACK after message processing\n- **JSON Support**: Automatic JSON serialization/deserialization\n- **Blocking Reads**: Efficient blocking reads with configurable timeouts\n- **Multiple Consumers**: Support for distributed message processing\n\n## Installation\n\nAdd this line to your application's Gemfile:\n\n```ruby\ngem 'redis-streams-pubsub'\n```\n\nAnd then execute:\n\n```bash\nbundle install\n```\n\nOr install it yourself as:\n\n```bash\ngem install redis-streams-pubsub\n```\n\n## Requirements\n\n- Ruby \u003e= 3.0\n- Redis \u003e= 5.0 (for Redis Streams support)\n- redis-client \u003e= 0.26\n\n## Quick Start\n\n### Publishing Messages\n\n```ruby\nrequire 'redis-streams-pubsub'\n\n# Option 1: Use a shorthand alias\nClient = Redis::Streams::PubSub::Client\n\npublisher = Client.new(url: \"redis://localhost:6379\")\n\n# Publish a message\npublisher.publish(\"notifications\", {\n  type: \"user_signup\",\n  user_id: 123,\n  email: \"user@example.com\"\n})\n```\n\n### Subscribing to Messages\n\n```ruby\nrequire 'redis-streams-pubsub'\n\n# Option 2: Include the module\ninclude Redis::Streams::PubSub\n\nsubscriber = Client.new(url: \"redis://localhost:6379\")\n\n# Subscribe and process messages\nsubscriber.subscribe(\"notifications\") do |message|\n  puts \"Received: #{message}\"\n  # Process the message\n  # Return :stop to exit the subscription loop\nend\n```\n\n## Usage\n\n### Shortening the Namespace\n\nThere are several ways to avoid typing the long namespace:\n\n```ruby\n# Option 1: Create an alias (recommended)\nClient = Redis::Streams::PubSub::Client\nclient = Client.new\n\n# Option 2: Include the module\ninclude Redis::Streams::PubSub\nclient = Client.new\n\n# Option 3: Assign to a local variable\nPubSub = Redis::Streams::PubSub\nclient = PubSub::Client.new\n```\n\n### Basic Publisher\n\n```ruby\nClient = Redis::Streams::PubSub::Client\n\nclient = Client.new(url: \"redis://localhost:6379\")\n\n# Publish messages to a topic\nclient.publish(\"events\", { event: \"page_view\", page: \"/home\" })\nclient.publish(\"events\", { event: \"button_click\", button: \"signup\" })\n```\n\n### Basic Subscriber\n\n```ruby\ninclude Redis::Streams::PubSub\n\nclient = Client.new(url: \"redis://localhost:6379\")\n\n# Subscribe to a topic\nclient.subscribe(\"events\") do |message|\n  puts \"Event: #{message['event']}\"\n  # Continue listening\nend\n```\n\n### Stopping a Subscription\n\nReturn `:stop` from the block to exit the subscription loop:\n\n```ruby\nclient.subscribe(\"events\") do |message|\n  puts \"Received: #{message}\"\n  \n  # Stop after processing a specific message\n  :stop if message['type'] == 'shutdown'\nend\n```\n\n### Custom Consumer Groups\n\nBy default, all subscribers use the same consumer group (`redis-streams-pubsub`), which means messages are distributed among subscribers (load balancing).\n\n```ruby\n# Subscribers in the same group share the workload\nsubscriber1.subscribe(\"events\", group: \"workers\") { |msg| process(msg) }\nsubscriber2.subscribe(\"events\", group: \"workers\") { |msg| process(msg) }\n\n# Subscribers in different groups each receive all messages\nsubscriber3.subscribe(\"events\", group: \"analytics\") { |msg| analyze(msg) }\nsubscriber4.subscribe(\"events\", group: \"logging\") { |msg| log(msg) }\n```\n\n### Custom Consumer ID\n\nEach subscriber gets a unique consumer ID by default. You can specify a custom one:\n\n```ruby\nclient = Redis::Streams::PubSub::Client.new(\n  url: \"redis://localhost:6379\",\n  consumer: \"worker-1\"\n)\n```\n\n### Error Handling\n\n```ruby\nbegin\n  client.subscribe(\"events\") do |message|\n    process_message(message)\n  end\nrescue Interrupt\n  puts \"Subscriber stopped\"\nrescue =\u003e e\n  puts \"Error: #{e.message}\"\nend\n```\n\n## How It Works\n\n### Consumer Groups\n\nThe gem uses Redis Streams consumer groups to manage message distribution:\n\n- Messages are added to a stream using `XADD`\n- Consumer groups track which messages have been delivered\n- Each consumer in a group receives different messages (load balancing)\n- Messages are automatically acknowledged after processing\n\n### Message Flow\n\n1. **Publisher** calls `publish(topic, payload)`\n   - Payload is serialized to JSON\n   - Message is added to the Redis Stream\n\n2. **Subscriber** calls `subscribe(topic)`\n   - Consumer group is created (if it doesn't exist)\n   - Subscriber blocks waiting for new messages\n   - When a message arrives, the block is called\n   - Message is automatically acknowledged\n\n### Blocking Behavior\n\nThe subscriber uses `XREADGROUP` with a 5-second block timeout. This means:\n- The subscriber waits up to 5 seconds for new messages\n- If no messages arrive, it loops and waits again\n- This is efficient and doesn't poll continuously\n\n## Examples\n\nSee the [examples](examples/) directory for complete working examples:\n\n- [publisher.rb](examples/publisher.rb) - Publishing messages\n- [subscriber.rb](examples/subscriber.rb) - Subscribing to messages\n- [README.md](examples/README.md) - Detailed examples documentation\n\nTo run the examples:\n\n```bash\n# Terminal 1: Start the subscriber\nruby examples/subscriber.rb\n\n# Terminal 2: Run the publisher\nruby examples/publisher.rb\n```\n\n## API Reference\n\n### `Redis::Streams::PubSub::Client`\n\n#### `initialize(url: \"redis://localhost:6379\", consumer: nil)`\n\nCreates a new client instance.\n\n**Parameters:**\n- `url` (String): Redis connection URL\n- `consumer` (String, optional): Custom consumer ID (auto-generated if not provided)\n\n#### `publish(topic, payload)`\n\nPublishes a message to a topic.\n\n**Parameters:**\n- `topic` (String): The topic/stream name\n- `payload` (Hash): Message payload (will be serialized to JSON)\n\n**Returns:** Redis message ID\n\n#### `subscribe(topic, group: DEFAULT_GROUP, \u0026block)`\n\nSubscribes to a topic and processes messages.\n\n**Parameters:**\n- `topic` (String): The topic/stream name\n- `group` (String): Consumer group name (default: \"redis-streams-pubsub\")\n- `block` (Block): Block to process each message\n\n**Block Parameters:**\n- `message` (Hash): Deserialized message payload\n\n**Block Return:**\n- Return `:stop` to exit the subscription loop\n- Return anything else to continue listening\n\n## Testing\n\nRun the test suite:\n\n```bash\nbundle exec rspec\n```\n\nRun RuboCop:\n\n```bash\nbundle exec rubocop\n```\n\n## Development\n\nAfter checking out the repo, run `bundle install` to install dependencies.\n\n## Contributing\n\n1. Fork it\n2. Create your feature branch (`git checkout -b my-new-feature`)\n3. Commit your changes (`git commit -am 'Add some feature'`)\n4. Push to the branch (`git push origin my-new-feature`)\n5. Create a new Pull Request\n\n## License\n\nThis project is available as open source under the terms of the MIT License.\n\n## Author\n\nDavide V.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdaemonzone%2Fredis-streams-pubsub","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdaemonzone%2Fredis-streams-pubsub","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdaemonzone%2Fredis-streams-pubsub/lists"}