{"id":13878712,"url":"https://github.com/testdouble/maybe_later","last_synced_at":"2025-07-16T14:32:52.128Z","repository":{"id":37400244,"uuid":"449773569","full_name":"testdouble/maybe_later","owner":"testdouble","description":"Run code after the current Rack response or Rails action completes","archived":false,"fork":false,"pushed_at":"2024-11-02T02:00:41.000Z","size":33,"stargazers_count":132,"open_issues_count":0,"forks_count":2,"subscribers_count":6,"default_branch":"main","last_synced_at":"2024-11-02T03:16:21.336Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"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/testdouble.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-01-19T16:39:54.000Z","updated_at":"2024-11-02T02:00:45.000Z","dependencies_parsed_at":"2022-08-02T22:00:45.216Z","dependency_job_id":null,"html_url":"https://github.com/testdouble/maybe_later","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/testdouble%2Fmaybe_later","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/testdouble%2Fmaybe_later/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/testdouble%2Fmaybe_later/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/testdouble%2Fmaybe_later/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/testdouble","download_url":"https://codeload.github.com/testdouble/maybe_later/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":226138849,"owners_count":17579496,"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":[],"created_at":"2024-08-06T08:01:57.446Z","updated_at":"2024-11-24T07:31:16.894Z","avatar_url":"https://github.com/testdouble.png","language":"Ruby","funding_links":[],"categories":["Ruby"],"sub_categories":[],"readme":"\u003cimg src=\"https://user-images.githubusercontent.com/79303/150394856-67252204-2857-412c-b379-851144776728.jpg\" width=\"90%\"/\u003e\n\n# maybe_later - get slow code out of your users' way\n\nMaybe you've been in this situation: you want to call some Ruby while responding\nto an HTTP request, but it's a time-consuming operation, its outcome won't\nimpact the response you send, and naively invoking it will result in a slower\npage load or API response for your users.\n\nIn almost all cases like this, Rubyists will reach for a [job\nqueue](https://edgeguides.rubyonrails.org/active_job_basics.html). And that's\nusually the right answer! But for relatively trivial tasks—cases where the\n_only_ reason you want to defer execution is a faster page load—creating a new\njob class and scheduling the work onto a queuing system can feel like overkill.\n\nIf this resonates with you, the `maybe_later` gem might be the best way to run\nthat code for you (eventually).\n\n##  Bold Font Disclaimer\n\n⚠️ **If the name `maybe_later` didn't make it clear, this gem does nothing to\nensure that your after-action callbacks actually run. If the code you're calling\nis very important, use [sidekiq](https://github.com/mperham/sidekiq) or\nsomething!** ⚠️\n\n## Setup\n\nAdd the gem to your Gemfile:\n\n```ruby\ngem \"maybe_later\"\n```\n\nIf you're using Rails, the gem's middleware will be registered automatically. If\nyou're not using Rails but _are_ using a rack-based server that supports\n[env[\"rack.after_reply\"]](https://github.com/rack/rack/issues/1060) (which\nincludes\n[puma](https://github.com/puma/puma/commit/be4a8336c0b4fc911b99d1ffddc4733b6f38d81d)\nand\n[unicorn](https://github.com/defunkt/unicorn/commit/673c15e3f020bccc0336838617875b26c9a45f4e)),\njust add `use MaybeLater::Middleware` to your `config.ru` file.\n\n## Usage\n\nUsing the gem is pretty straightforward, just pass the code you want to run to\n`MaybeLater.run` as a block:\n\n```ruby\nMaybeLater.run {\n  AnalyticsService.send_telemetry!\n}\n```\n\nEach block passed to `MaybeLater.run` will be run after the HTTP response is\nsent.\n\nIf the code you're calling needs to be executed in the same thread that's\nhandling the HTTP request, you can pass `inline: true`:\n\n```ruby\nMaybeLater.run(inline: true) {\n  # Thread un-safe code here\n}\n```\n\nAnd your code will be run right after the HTTP response is sent. Additionally,\nif there are any inline tasks to be run, the response will include a\n`\"Connection: close` header so that the browser doesn't sit waiting on its\nconnection while the web thread executes the deferred code.\n\n_[**Warning about `inline`:** running\nslow inline tasks runs the risk of saturating the server's available threads\nlistening for connections, effectively shifting the slowness of one request onto\nlater ones!]_\n\n\n## Configuration\n\nThe gem offers a few configuration options:\n\n```ruby\nMaybeLater.config do |config|\n  # Will be called if a block passed to MaybeLater.run raises an error\n  config.on_error = -\u003e(error) {\n    # e.g. Honeybadger.notify(error)\n  }\n\n  # Will run after each `MaybeLater.run {}` block, even if it errors\n  config.after_each = -\u003e {}\n\n  # By default, tasks will run in a fixed thread pool. To run them in the\n  # thread dispatching the HTTP response, set this to true\n  config.inline_by_default = false\n\n  # How many threads to allocate to the fixed thread pool (default: 5)\n  config.max_threads = 5\n\n  # If set to true, will invoke the after_reply tasks even if the server doesn't\n  # provide a rack.after_reply array.\n  # One reason to do this is if you are using Rails controller tests\n  # (with no webserver) rather than system tests.\n  # config.invoke_even_if_server_is_unsupported = Rails.env.test?\n  config.invoke_even_if_server_is_unsupported = false\nend\n```\n\n## Help! Why isn't my code running?\n\nIf the blocks you pass to `MaybeLater.run` aren't running, possible\nexplanations include:\n\n* Because the blocks passed to `MaybeLater.run` are themselves stored in a\n  thread-local array, if you invoke `MaybeLater.run` from a thread that isn't\n  handling with a Rack request, the block will never run\n* If your Rack server doesn't support `rack.after_reply`, the blocks will never\n  run\n* If the block _is_ running and raising an error, you'll only know about it if\n  you register a `MaybeLater.config.on_error` handler\n\n## Acknowledgement\n\nThe idea for this gem was triggered by [this\ntweet](https://twitter.com/julikt/status/1483585327277223939) in reply to [this\nquestion](https://twitter.com/searls/status/1483572597686259714). Also, many\nthanks to [Matthew Draper](https://github.com/matthewd) for answering a bunch of\nquestions I had while implementing this.\n\n## Code of Conduct\n\nThis project follows Test Double's [code of\nconduct](https://testdouble.com/code-of-conduct) for all community interactions,\nincluding (but not limited to) one-on-one communications, public posts/comments,\ncode reviews, pull requests, and GitHub issues. If violations occur, Test Double\nwill take any action they deem appropriate for the infraction, up to and\nincluding blocking a user from the organization's repositories.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftestdouble%2Fmaybe_later","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftestdouble%2Fmaybe_later","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftestdouble%2Fmaybe_later/lists"}