{"id":50674057,"url":"https://github.com/webermarci/roar","last_synced_at":"2026-06-08T14:30:45.789Z","repository":{"id":345197593,"uuid":"1153765808","full_name":"webermarci/roar","owner":"webermarci","description":"Distributed pub/sub for Gleam with automatic cluster synchronization across BEAM nodes","archived":false,"fork":false,"pushed_at":"2026-02-10T18:20:11.000Z","size":9,"stargazers_count":0,"open_issues_count":4,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-18T19:10:36.087Z","etag":null,"topics":["distributed","gleam","pubsub"],"latest_commit_sha":null,"homepage":"https://hex.pm/packages/roar","language":"Gleam","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/webermarci.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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":"2026-02-09T16:41:48.000Z","updated_at":"2026-02-10T18:20:14.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/webermarci/roar","commit_stats":null,"previous_names":["webermarci/roar"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/webermarci/roar","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webermarci%2Froar","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webermarci%2Froar/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webermarci%2Froar/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webermarci%2Froar/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/webermarci","download_url":"https://codeload.github.com/webermarci/roar/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webermarci%2Froar/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34067347,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-08T02:00:07.615Z","response_time":111,"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":["distributed","gleam","pubsub"],"created_at":"2026-06-08T14:30:44.003Z","updated_at":"2026-06-08T14:30:45.784Z","avatar_url":"https://github.com/webermarci.png","language":"Gleam","funding_links":[],"categories":[],"sub_categories":[],"readme":"# roar\n\n[![Package Version](https://img.shields.io/hexpm/v/roar)](https://hex.pm/packages/roar)\n[![Hex Docs](https://img.shields.io/badge/hex-docs-ffaff3)](https://hexdocs.pm/roar/)\n![Status: Experimental](https://img.shields.io/badge/status-experimental-orange)\n![Stability: Unstable](https://img.shields.io/badge/stability-unstable-red)\n\n\u003e ⚠️ **Warning:** This project is experimental and unstable. APIs may change significantly between versions.\n\nLightweight distributed pub/sub for Gleam on Erlang with automatic cluster synchronization.\n\nRoar enables process-local and cluster-wide message broadcasting with automatic scope isolation, supporting both streaming subscriptions and callback-based handlers.\n\n## Features\n\n- 🌍 **Distributed by default** - Messages automatically sync across all nodes in your cluster\n- 🎯 **Scope isolation** - Multiple independent pub/sub systems in the same cluster\n- 📦 **Simple API** - Subscribe with callbacks or buffered streams\n- 🛡️ **Memory safe** - Configurable buffer capacity prevents runaway memory growth\n- ⚡ **BEAM native** - Built on Erlang's distribution primitives\n\n## Installation\n\nAdd `roar` to your Gleam project:\n\n```sh\ngleam add roar\n```\n\n## Quick Start\n\n```gleam\nimport roar\n\npub fn main() {\n  // Create a router with buffer capacity and scope\n  let router = roar.new(capacity: 100, scope: \"my_app\")\n  \n  // Subscribe to a topic\n  let sub = roar.subscribe(router, \"events\")\n  \n  // Publish a message (reaches ALL nodes in \"my_app\" scope)\n  roar.publish(router, \"events\", \"Hello, cluster!\")\n  \n  // Receive messages\n  case sub.receive() {\n    Ok(message) -\u003e io.println(message)\n    Error(Nil) -\u003e io.println(\"No messages\")\n  }\n  \n  sub.cancel()\n}\n```\n\n## Usage\n\n### Callback-based subscriptions\n\n```gleam\nlet cancel = roar.on(router, \"notifications\", fn(msg) {\n  io.println(\"Received: \" \u003c\u003e msg)\n})\n\nroar.publish(router, \"notifications\", \"New user signed up!\")\n\ncancel()\n```\n\n### Buffered subscriptions\n\n```gleam\nlet sub = roar.subscribe(router, \"events\")\n\nroar.publish(router, \"events\", \"Event 1\")\nroar.publish(router, \"events\", \"Event 2\")\n\n// Messages are buffered, read at your own pace\nlet assert Ok(\"Event 1\") = sub.receive()\nlet assert Ok(\"Event 2\") = sub.receive()\n\nsub.cancel()\n```\n\n### Multiple topics\n\n```gleam\nlet router = roar.new(capacity: 50, scope: \"chat\")\n\nlet messages = roar.subscribe(router, \"messages\")\nlet alerts = roar.subscribe(router, \"alerts\")\n\nroar.publish(router, \"messages\", \"Hello!\")\nroar.publish(router, \"alerts\", \"Server restarting\")\n\n// Each subscription only receives its topic's messages\n```\n\n### Scope isolation\n\n```gleam\n// Different scopes don't interfere with each other\nlet app_router = roar.new(capacity: 100, scope: \"app\")\nlet admin_router = roar.new(capacity: 100, scope: \"admin\")\n\nroar.subscribe(app_router, \"events\")    // Only sees \"app\" scope\nroar.subscribe(admin_router, \"events\")  // Only sees \"admin\" scope\n```\n\n## How It Works\n\nRoar uses [Whisper](https://hexdocs.pm/whisper/) for local pub/sub and Erlang's `pg` (process groups) for cluster-wide distribution. When you publish a message:\n\n1. **Local delivery** - Delivered immediately to subscribers on the same node\n2. **Remote delivery** - Forwarded to all nodes in the same scope via process groups\n3. **No duplicates** - Each subscriber receives exactly one copy\n\nThe `capacity` parameter protects against memory issues by limiting buffered messages per subscription. If a subscriber is too slow, old messages are dropped to prevent memory exhaustion.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwebermarci%2Froar","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwebermarci%2Froar","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwebermarci%2Froar/lists"}