{"id":29271574,"url":"https://github.com/senotrusov/redis-call","last_synced_at":"2026-05-08T10:34:14.551Z","repository":{"id":1629305,"uuid":"2347585","full_name":"senotrusov/redis-call","owner":"senotrusov","description":"Redis access library for Ruby with thread-aware connections, handy API for key name construction, transactions and queues.","archived":false,"fork":false,"pushed_at":"2017-04-23T19:37:39.000Z","size":36,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-12-18T08:19:22.290Z","etag":null,"topics":["json","optimistic-locking","queue","redis","ruby","thread","transaction"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/senotrusov.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2011-09-08T09:56:59.000Z","updated_at":"2025-03-30T00:44:53.000Z","dependencies_parsed_at":"2022-08-20T16:00:52.980Z","dependency_job_id":null,"html_url":"https://github.com/senotrusov/redis-call","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/senotrusov/redis-call","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/senotrusov%2Fredis-call","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/senotrusov%2Fredis-call/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/senotrusov%2Fredis-call/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/senotrusov%2Fredis-call/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/senotrusov","download_url":"https://codeload.github.com/senotrusov/redis-call/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/senotrusov%2Fredis-call/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32776863,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-08T08:22:46.396Z","status":"ssl_error","status_checked_at":"2026-05-08T08:22:45.650Z","response_time":54,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["json","optimistic-locking","queue","redis","ruby","thread","transaction"],"created_at":"2025-07-05T00:00:56.298Z","updated_at":"2026-05-08T10:34:14.526Z","avatar_url":"https://github.com/senotrusov.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# RedisCall\n\nA [Redis](https://redis.io) access library, which provides:\n\n* Connection management\n  * Per-thread connection\n  * Shared between threads connection\n* Key names construction\n* Transactions\n  * Queued result handling\n  * Retry on optimistic lock fail\n* Queues\n  * message handling with backup queue\n  * restore from backup queue\n  * queues in Rails controllers\n  * messages as REST resources\n  * message handling in separate process\n  * graceful stop of blocking operations\n* JSON encode/decode\n* And nice ruby API\n\nIt use [Hiredis](https://github.com/redis/hiredis) to connect to [Redis](https://redis.io).\n\n\n## Basic operations\n```ruby\nr = RedisCall.new\n\nprefix = r.key('foo')\n\n# set the 'foo.bar.qux' to 'content' with 1 day expiration\nr.setex prefix+:bar+'qux', 1.day, 'content'\nr.setex prefix/:bar/'qux', 1.day, 'content'\n\n# get 'foo.bar.qux'\nr.get prefix/:bar/'qux'\n```\n\n\n## Custom storage class\n\n```ruby\nclass MyStorage \u003c RedisCall\n  def store key_name, value\n    multi do\n      del key(:prefix)/key_name/:some_state\n      set key(:prefix)/key_name, value\n    end\n  end\nend\n```\n\n\n# Queues\n\n## Basic operations\n\n```ruby\nqueue = RedisQueue::Base.new('foo')\nqueue.push(hello: 'darling')\n\nqueue.name\nqueue.length\nqueue.backup_length\n\nqueue.pop_all\nqueue.backup_elements\nqueue.backed_up_pop_all\n\nsubqueue = RedisQueue::Base.new(queue.name/:subqueue)\n```\n\n\n## Message handler process\n\nHere is sample standalone message handler process with backup queue.\nTo handle process-related functionality (start/stop/watchdog), [workety](https://github.com/senotrusov/workety) library is used.\n\n```ruby\nclass Handler\n  def start\n    @queue = RedisQueue::Base.new 'queue_name', connect: true\n    @queue.restore_backup\n\n    @handler = Thread.networkety do\n      loop do\n        @queue.backed_up_blocking_pop do |message|\n          puts message.inspect\n        end\n      end\n    end\n  end\n\n  def join\n    @handler.log_join \"Handler thread joined\"\n  end\n\n  def stop\n    @queue.disconnect @handler\n  end\nend\n```\n\n\n## Serialization and custom queue class\n\nRedis operates with string as a queue element. To transfer Ruby classes, serialization technique may be used.\nRedisCall use JSON as the transfer format.\nIn case when you want to transfer not Hash but some custom class (say MyElement),\nyou may define your own queue class to handle that:\n\n```ruby\nclass MyQueue \u003c RedisQueue::Base\n  def encode element\n    super(element.as_json(:except =\u003e [:serialized]))\n  end\n\n  def decode raw\n    MyElement.new(super(raw))\n  end\nend\n```\n\n\n## Queue metadata\n\nYou may store queue metadata in ``config/redis_queue.yml`` file:\n\n```yml\nqueue_name:\n  attr: value\n```\n\nand retrieve it:\n\n``` ruby\nRedisQueue::Base.new('queue_name').config[:attr]\n# =\u003e 'value'\n```\n\n\n## Queues in Rails controllers\n\n### A list of queues\n\n```ruby\nclass QueueListController\n  # Queue names currently are not checked for funny characters by library,\n  # so a potential of Redis command injection exists.\n  def filtered_id\n    params[:id].tr('^A-Za-z0-9.', '')\n  end\n\n  def index\n    @queues = RedisQueue::Base.all\n  end\n\n  def destroy\n    @queue = RedisQueue::Base.find filtered_id\n    @queue.destroy\n  end\nend\n```\n\n\n### Messages\n\n```ruby\nclass MessagesController\n  def queue\n    @queue ||= RedisQueue::Base.new('input')\n  end\n\n  def output_queue\n    @output_queue ||= RedisQueue::Base.new('output')\n  end\n\n  def raw_message\n    params[:message][:serialized]\n  end\n\n  def index\n    @messages = queue.elements\n    @messages = queue.backup_elements\n\n    @messages = queue.pop_all\n    @messages = queue.backed_up_pop_all\n  end\n\n  def update\n    queue.insist do # Retry on optimistic lock fail\n      queue.watch_backup # Optimistic locking\n\n      if queue.raw_backup_elements.include? raw_message\n        @message = queue.decode raw_message\n\n        if @message.valid?\n\n          queue.multi do\n            queue.remove_raw_backup_element raw_message\n            output_queue.push \"some message\"\n          end\n\n          respond_to do |format|\n            format.html { render :nothing =\u003e true, status: :created }\n          end\n        else\n          respond_to do |format|\n            format.html { render partial: 'form', :locals =\u003e {message: @message}, status: :unprocessable_entity }\n          end\n        end\n      else\n        respond_to do |format|\n          format.html { render text: \"The message you are trying to update is gone\", status: :gone }\n        end\n      end\n    end\n  end\n\n  def destroy\n    queue.remove_raw_element raw_message\n  end\nend\n```\n\n\n# Environment details\n\n## Connection configuration\n\nBy default, Redis is expected to be found listening the 127.0.0.1:6379, but that can be configured in ``config/redis_call.yml``\n\n```yml\ndevelopment:\n  host: localhost\n  port: 6379\n\nproduction:\n  host: localhost\n  port: 6379\n\ntest:\n  host: localhost\n  port: 6379\n```\n\n\n## Forks and Unicorn webserver\n\nForking the process require reconnection. For Unicorn webserver it may be done by stating in ``config/unicorn.rb``:\n\n```ruby\nbefore_fork do |server, worker|\n  RedisCall.new.disconnect\nend\n\nafter_fork do |server, worker|\n  RedisCall.new.connect\nend\n```\n\n\n## Copyright and License\n\n```\nCopyright 2011 Stanislav Senotrusov\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n```\n\n## Contributing\n\nPlease see our [Contributing Guidelines](CONTRIBUTING.md) for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsenotrusov%2Fredis-call","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsenotrusov%2Fredis-call","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsenotrusov%2Fredis-call/lists"}