{"id":20236374,"url":"https://github.com/onyxframework/eda","last_synced_at":"2025-04-10T19:02:23.728Z","repository":{"id":95000677,"uuid":"164882035","full_name":"onyxframework/eda","owner":"onyxframework","description":"Event-Driven Architecture framework to build reactive apps 💣","archived":false,"fork":false,"pushed_at":"2019-08-13T09:48:43.000Z","size":125,"stargazers_count":8,"open_issues_count":1,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-24T16:43:44.622Z","etag":null,"topics":["crystal","event-driven","events","onyxframework","shard"],"latest_commit_sha":null,"homepage":"https://onyxframework.com/eda","language":"Crystal","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/onyxframework.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}},"created_at":"2019-01-09T14:52:19.000Z","updated_at":"2024-05-09T10:15:59.000Z","dependencies_parsed_at":"2023-06-11T13:15:41.511Z","dependency_job_id":null,"html_url":"https://github.com/onyxframework/eda","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/onyxframework%2Feda","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/onyxframework%2Feda/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/onyxframework%2Feda/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/onyxframework%2Feda/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/onyxframework","download_url":"https://codeload.github.com/onyxframework/eda/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248278835,"owners_count":21077328,"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","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":["crystal","event-driven","events","onyxframework","shard"],"created_at":"2024-11-14T08:20:26.330Z","updated_at":"2025-04-10T19:02:23.717Z","avatar_url":"https://github.com/onyxframework.png","language":"Crystal","funding_links":["https://www.patreon.com/vladfaust"],"categories":[],"sub_categories":[],"readme":"\u003ca href=\"https://onyxframework.org\"\u003e\u003cimg width=\"100\" height=\"100\" src=\"https://onyxframework.org/img/logo.svg\"\u003e\u003c/a\u003e\n\n# Onyx::EDA\n\n[![Built with Crystal](https://img.shields.io/badge/built%20with-crystal-000000.svg?style=flat-square)](https://crystal-lang.org/)\n[![Travis CI build](https://img.shields.io/travis/onyxframework/eda/master.svg?style=flat-square)](https://travis-ci.org/onyxframework/eda)\n[![Docs](https://img.shields.io/badge/docs-online-brightgreen.svg?style=flat-square)](https://docs.onyxframework.org/eda)\n[![API docs](https://img.shields.io/badge/api_docs-online-brightgreen.svg?style=flat-square)](https://api.onyxframework.org/eda)\n[![Latest release](https://img.shields.io/github/release/onyxframework/eda.svg?style=flat-square)](https://github.com/onyxframework/eda/releases)\n\nAn Event-Driven Architecture framework to build reactive apps.\n\n## About 👋\n\nOnyx::EDA is an [Event-Driven Architecture](https://en.wikipedia.org/wiki/Event-driven_architecture) framework. It allows to emit certain *events* and subscribe to them.\n\nCurrently the framework has these *channels* implemented:\n\n* [Memory channel](https://api.onyxframework.org/eda/Onyx/EDA/Channel/Memory.html)\n* [Redis channel](https://api.onyxframework.org/eda/Onyx/EDA/Channel/Redis.html) (working on [Redis streams](https://redis.io/topics/streams-intro))\n\nOnyx::EDA is a **real-time** events framework. It does not process events happend in the past and currently does not care about reliability in case of third-party service dependant channels (i.e. Redis).\n\n👍 The framework is a great choice for reactive and/or distributed applications, effectively allowing to have multiple loosely-coupled components which do not directly interact with each other, but rely on events instead.\n\n👎 However, Onyx::EDA is not a good choice for tasks requiring reliability, for example, background processing. If a Redis consumer dies during processing, the event is likely to not be processed. This behaviour may change in the future.\n\n## Installation 📥\n\nAdd this to your application's `shard.yml`:\n\n```yaml\ndependencies:\n  onyx:\n    github: onyxframework/onyx\n    version: ~\u003e 0.6.0\n  onyx-eda:\n    github: onyxframework/eda\n    version: ~\u003e 0.4.0\n```\n\nThis shard follows [Semantic Versioning v2.0.0](http://semver.org/), so check [releases](https://github.com/vladfaust/timer.cr/releases) and change the `version` accordingly.\n\n\u003e Note that until Crystal is officially released, this shard would be in beta state (`0.*.*`), with every **minor** release considered breaking. For example, `0.1.0` → `0.2.0` is breaking and `0.1.0` → `0.1.1` is not.\n\n## Usage 💻\n\nFirst of all, you must require channels you'd need:\n\n```crystal\nrequire \"onyx/eda/memory\"\nrequire \"onyx/eda/redis\"\n```\n\nThen define events to emit:\n\n```crystal\nstruct MyEvent\n  include Onyx::EDA::Event\n\n  getter foo\n\n  def initialize(@foo : String)\n  end\nend\n```\n\n### Basic subscribing\n\nYou must define a block which would be run on incoming event:\n\n```crystal\nOnyx::EDA.memory.subscribe(MyEvent) do |event|\n  pp event.foo\nend\n```\n\nSubscribing and emitting are **asynchronous** operations. You must then `yield` the control with `sleep` or `Fiber.yield` to let notifications reach their subscriptions:\n\n```crystal\nOnyx::EDA.memory.emit(MyEvent.new(\"bar\"))\nsleep(1)\n```\n\nOutput, as expected:\n\n```\nbar\n```\n\nYou can cancel a subscription as well:\n\n```crystal\nsub = Onyx::EDA.memory.subscribe(MyEvent) do |event|\n  pp event.foo\nend\n\nsub.unsubscribe\n```\n\n### Subscribing with filters\n\nYou can filter incoming events and run the subscription block only if the event's getters match the filter:\n\n```crystal\n# Would only put \"bar\"\nOnyx::EDA.memory.subscribe(MyEvent, foo: \"bar\") do |event|\n  pp event.foo\nend\n\nOnyx::EDA.memory.emit(MyEvent.new(\"qux\")) # Would not notify the subscription above\nOnyx::EDA.memory.emit(MyEvent.new(\"bar\")) # OK, condition is met\n```\n\n### Consuming\n\nYou can create an event consumption instead of a subscription. From docs:\n\n\u003e Consumption differs from subscription in a way that only a single consuming subscription instance with certain *consumer_id* among all this channel subscribers would be notified about an event after it successfully acquires a lock. The lock implementation differs in channels.\n\nIn this code only **one** `\"bar\"` will be put, because both subscriptions have `\"MyConsumer\"` as the consumer ID:\n\n```crystal\nsub1 = Onyx::EDA.memory.subscribe(MyEvent, \"MyConsumer\") do |event|\n  puts event.foo\nend\n\nsub2 = Onyx::EDA.memory.subscribe(MyEvent, \"MyConsumer\") do |event|\n  puts event.foo\nend\n\nOnyx::EDA.memory.emit(MyEvent.new(\"bar\"))\n```\n\nThe consuming works as expected with [Redis channel](https://api.onyxframework.org/eda/Onyx/EDA/Channel/Redis.html) as well. It relies on [Redis streams](https://redis.io/topics/streams-intro). However, if a consumer crashes, then no other consumer with the same ID would try to process this event anymore (i.e. the behavior is unreliable). This may change in the future.\n\nNote that you can not use event filters while consuming.\n\n### Awaiting\n\nIt is possible to await for a certain event to happen in a **blocking** manner:\n\n```crystal\n# Will block the execution until the event is received\nOnyx::EDA.memory.await(MyEvent) do |event|\n  pp event.foo\nend\n```\n\nIt is particularly useful in `select` blocks:\n\n```crystal\nselect\nwhen event = Onyx::EDA.memory.await(MyEvent)\n  pp event.foo\nwhen Timer.new(30.seconds)\n  raise \"Timeout!\"\nend\n```\n\n*💡 See [timer.cr](https://github.com/vladfaust/timer.cr) for a timer shard.*\n\nYou can use filters with awaiting, making it possible to wait for a specific event hapenning:\n\n```crystal\nrecord MyEventHandled, parent_event_id : UUID do\n  include Onyx::EDA::Event\nend\n\nevent = Onyx::EDA.redis.emit(MyEvent.new(\"bar\"))\n\nselect\nwhen event = Onyx::EDA.redis.await(MyEventHandled, parent_event_id: event.event_id)\n  puts \"Handled\"\nwhen Timer.new(30.seconds)\n  raise \"Timeout!\"\nend\n```\n\n### `Subscriber` and `Consumer`\n\nYou can include the `Subscriber(T)` and `Consumer(T)` modules into an object, turning it into an event (`T`) subscriber or consumer. It must implement `handle(event : T)` and be explicitly subscribed to a channel.\n\n```crystal\nclass Actor::Logger\n  include Onyx::EDA::Subscriber(Event::User::Registered)\n  include Onyx::EDA::Consumer(Event::Payment::Successfull)\n\n  # This method will be called in *all* Actor::Logger instances\n  def handle(event : Event::User::Registered)\n    log_into_terminal(\"New user with id #{event.id}\")\n  end\n\n  # This method will be called in only *one* Actor::Logger instance\n  def handle(event : Event::Payment::Successfull)\n    send_email(\"admin@example.com\", \"New payment of $#{event.amount}\")\n  end\nend\n\nactor = Actor::Logger.new\nactor.subscribe(Onyx::EDA.memory)   # Non-blocking method\nactor.unsubscribe(Onyx::EDA.memory) # Can be unsubscribed as well\n```\n\n## Documentation 📚\n\nThe documentation is available online at [docs.onyxframework.org/eda](https://docs.onyxframework.org/eda).\n\n## Community 🍪\n\nThere are multiple places to talk about Onyx:\n\n* [Gitter](https://gitter.im/onyxframework)\n* [Twitter](https://twitter.com/onyxframework)\n\n## Support 🕊\n\nThis shard is maintained by me, [Vlad Faust](https://vladfaust.com), a passionate developer with years of programming and product experience. I love creating Open-Source and I want to be able to work full-time on Open-Source projects.\n\nI will do my best to answer your questions in the free communication channels above, but if you want prioritized support, then please consider becoming my patron. Your issues will be labeled with your patronage status, and if you have a sponsor tier, then you and your team be able to communicate with me privately in [Twist](https://twist.com). There are other perks to consider, so please, don't hesistate to check my Patreon page:\n\n\u003ca href=\"https://www.patreon.com/vladfaust\"\u003e\u003cimg height=\"50\" src=\"https://onyxframework.org/img/patreon-button.svg\"\u003e\u003c/a\u003e\n\nYou could also help me a lot if you leave a star to this GitHub repository and spread the word about Crystal and Onyx! 📣\n\n## Contributing\n\n1. Fork it ( https://github.com/onyxframework/eda/fork )\n2. Create your feature branch (git checkout -b my-new-feature)\n3. Commit your changes (git commit -am 'feat: some feature') using [Angular style commits](https://github.com/angular/angular/blob/master/CONTRIBUTING.md#commit)\n4. Push to the branch (git push origin my-new-feature)\n5. Create a new Pull Request\n\n## Contributors\n\n- [Vlad Faust](https://github.com/vladfaust) - creator and maintainer\n\n## Licensing\n\nThis software is licensed under [MIT License](LICENSE).\n\n[![Open Source Initiative](https://upload.wikimedia.org/wikipedia/commons/thumb/4/42/Opensource.svg/100px-Opensource.svg.png)](https://opensource.org/licenses/MIT)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fonyxframework%2Feda","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fonyxframework%2Feda","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fonyxframework%2Feda/lists"}