{"id":19780798,"url":"https://github.com/gabrieljoelc/la_gear","last_synced_at":"2026-06-17T23:31:24.795Z","repository":{"id":148620338,"uuid":"471248541","full_name":"gabrieljoelc/la_gear","owner":"gabrieljoelc","description":"Use conventions to generate publish/subscribe workers","archived":false,"fork":false,"pushed_at":"2022-03-18T05:59:04.000Z","size":27,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-08-17T13:42:13.675Z","etag":null,"topics":["distributed-systems","pubsub","rabbitmq","redis","ruby","sidekiq"],"latest_commit_sha":null,"homepage":"","language":"Ruby","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/gabrieljoelc.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","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":"2022-03-18T05:38:24.000Z","updated_at":"2022-03-18T16:29:59.000Z","dependencies_parsed_at":"2023-05-20T17:31:11.689Z","dependency_job_id":null,"html_url":"https://github.com/gabrieljoelc/la_gear","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/gabrieljoelc/la_gear","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gabrieljoelc%2Fla_gear","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gabrieljoelc%2Fla_gear/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gabrieljoelc%2Fla_gear/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gabrieljoelc%2Fla_gear/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gabrieljoelc","download_url":"https://codeload.github.com/gabrieljoelc/la_gear/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gabrieljoelc%2Fla_gear/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34470322,"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-17T02:00:05.408Z","response_time":127,"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-systems","pubsub","rabbitmq","redis","ruby","sidekiq"],"created_at":"2024-11-12T05:41:10.856Z","updated_at":"2026-06-17T23:31:24.777Z","avatar_url":"https://github.com/gabrieljoelc.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# L.A. Gear\n\nThis gem has two primary purposes:\n* Allowing you to define one worker class that has your [`sneakers`](https://github.com/jondot/sneakers) worker queue configuration and the [`sidekiq`](https://github.com/mperham/sidekiq) `perform` method that actually processes the message.\n* DRYing up your `sneakers` configuration by using a conventions.\n\nHere are some other features:\n* Messages are deserialized as JSON by default and the properties are passed to Sidekiq's `perform_async` method\n* Out-of-the-box configuration of `sneakers` for multiple RabbitMQ subscribers\n* An alternative to the `Sneakers::Publisher#publish` method that allows you to pass in more options when publishing to a RabbitMQ exchange\n* Helper methods for configuring `sneakers`\n* Support for configuring `sneakers` with [BigWig](http://bigwig.io/)\n\nDISCLAIMER: This repo contains the source code from the [la_gear](https://rubygems.org/gems/la_gear) gem owned by [giftcardzen](https://rubygems.org/profiles/giftcardzen). This was an account I created while a software engineer at Giftcard Zen. Giftcard Zen was [acquired by RetailMeNot in 2015](https://www.crunchbase.com/acquisition/whale-shark-media-acquires-giftcard-zen--18806c45). RetailMeNot took ownership of the account and the open source projects under the [giftcardzen](https://github.com/giftcardzen) GitHub organization, including the la_gear repo. Unfortunately, RetailMeNot deleted the organization including all open source repos without transferring ownership to contributors.\n\nI finally got around to pulling the source from the gem and pushing it here, mostly for posterity. This represents a piece of my career growth in architecting distributed systems communicating via publish/subscribe.\n\n## Installation\n\nAdd this line to your application's Gemfile:\n\n    gem 'la_gear'\n\nAnd then execute:\n\n    $ bundle\n\nOr install it yourself as:\n\n    $ gem install la_gear\n\n## Usage\n\nInstead of `include Sneakers::Worker` in your workers, use `include LaGear::Worker`. Then all of your queues and routing key bindings will automatically use an `Sneakers::Config[:app_name]` plus the class name of your worker as your queue name and the class name of your worker as the routing key. For example,\n```ruby\nSneakers.configure app_name: 'pogs_are_awesome'\n\nclass BoKnows\n  include LaGear::Worker\n\n  def perform(baseball, football)\n    # process message ...\n  end\nend\n```\nwould by default result in the following 2 queue names:\n\n- `pogs_are_awesome.bo_knows`\n- `pogs_are_awesome.bo_knows.retry`\n\nThe default routing key would be: `bo_knows`. This allows for multiple consumer queue bindings for a direct exchange (see the Multiple Bindings section of https://www.rabbitmq.com/tutorials/tutorial-four-ruby.html). The `.retry` is for if you are using [dead letter exchanges](https://www.rabbitmq.com/dlx.html) and [message expirations](https://www.rabbitmq.com/ttl.html) to perform retries (which you should). Just call the `subscribes_to` method to override the convention-based defaults like so:\n\n```ruby\nclass PowerRanger\n  include LaGear::Worker\n\n  subscribes_to 'bo_knows'\n\n  def perform(red, yellow)\n    # process message...\n  end\nend\n```\n\nOr subscribe to multiple routing keys:\n\n```ruby\nsubscribes_to ['bo_knows', 'pump_it_up']\n```\n\nAlso, notice in the example above that we don't define a `work` method for `Sneakers::Worker`. That's because `LaGear::Worker` defines it for you. All the method does is deserialize your RabbitMQ message (defaults to JSON) and pass each of the properties as a parameters to Sidekiq's `perform_async` method to process the message. Put your message processing code in a `perform` method instead. That's the method that Sidekiq invokes when it actually processes the message that `LaGear::Worker#work` sent to it.\n\nYou can also use the conventions to create versioned workers to more easily handle backwards compatibility when message parameters change. This module/class:\n\n```ruby\nmodule BoKnows\n  class V1\n    def perform\n      # process message...\n    end\n  end\nend\n```\n\nwould create the routing key `bo_knows.v1` and these queue names:\n\n- `pogs_are_awesome.bo_knows.v1`\n- `pogs_are_awesome.bo_knows.v1.retry`\n\nOne caveat with `subscribes_to` and versioned workers is that the routing key must be manually incremented when a handler's version increments. If a worker `subscribes_to 'bo_knows.v1'`, and the `bo_knows.v1` message type increments to `bo_knows.v2`, you should create a new version of the worker that subscribes to `bo_knows.v2`.\n\n### The Bus\n\nThere is also a `LaGear::Bus` class which is an alternative to the `Sneakers::Publisher`. It adds an `opts` parameter to the `publish` method, allowing you to pass the options you would pass to the `bunny` exchange publish [method](http://reference.rubybunny.info/Bunny/Exchange.html#publish-instance_method) (see http://reference.rubybunny.info/Bunny/Exchange.html#publish-instance_method for the list of options). It also allows you use a common way to publish messages:\n\n- `LaGear::Bus.publish('bo_knows', baseball: 'royals', football: 'cowboys')`\n- `LaGear::Bus.publish('bo_knows', { baseball: 'royals', football: 'cowboys' }, version: 2)` - will publish to the exchange with the `bo_knows.v2` routing key\n- `LaGear::Bus.publish_in(1.day, 'bo_knows', baseball: 'royals', football: 'cowboys')`\n- `LaGear::Bus.publish_at(1.day.from_now, 'bo_knows', baseball: 'royals', football: 'cowboys')`\n- `LaGear::Bus.publish_local('bo_knows_local', baseball: 'royals', football: 'cowboys')` - this is for local only (`include Sidekiq::Worker`) workers\n- `LaGear::Bus.publish_local_in('bo_knows', { baseball: 'royals', football: 'cowboys' }, 1.day)`\n\n## Contributing\n\n1. Fork it ( https://github.com/[my-github-username]/la_gear/fork )\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","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgabrieljoelc%2Fla_gear","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgabrieljoelc%2Fla_gear","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgabrieljoelc%2Fla_gear/lists"}