Code Monkey home page Code Monkey logo

maybe_later's Introduction

maybe_later - get slow code out of your users' way

Maybe you've been in this situation: you want to call some Ruby while responding to an HTTP request, but it's a time-consuming operation, its outcome won't impact the response you send, and naively invoking it will result in a slower page load or API response for your users.

In almost all cases like this, Rubyists will reach for a job queue. And that's usually the right answer! But for relatively trivial tasks—cases where the only reason you want to defer execution is a faster page load—creating a new job class and scheduling the work onto a queuing system can feel like overkill.

If this resonates with you, the maybe_later gem might be the best way to run that code for you (eventually).

Bold Font Disclaimer

⚠️ If the name maybe_later didn't make it clear, this gem does nothing to ensure that your after-action callbacks actually run. If the code you're calling is very important, use sidekiq or something! ⚠️

Setup

Add the gem to your Gemfile:

gem "maybe_later"

If you're using Rails, the gem's middleware will be registered automatically. If you're not using Rails but are using a rack-based server that supports env["rack.after_reply"] (which includes puma and unicorn), just add use MaybeLater::Middleware to your config.ru file.

Usage

Using the gem is pretty straightforward, just pass the code you want to run to MaybeLater.run as a block:

MaybeLater.run {
  AnalyticsService.send_telemetry!
}

Each block passed to MaybeLater.run will be run after the HTTP response is sent.

If the code you're calling needs to be executed in the same thread that's handling the HTTP request, you can pass inline: true:

MaybeLater.run(inline: true) {
  # Thread un-safe code here
}

And your code will be run right after the HTTP response is sent. Additionally, if there are any inline tasks to be run, the response will include a "Connection: close header so that the browser doesn't sit waiting on its connection while the web thread executes the deferred code.

[Warning about inline: running slow inline tasks runs the risk of saturating the server's available threads listening for connections, effectively shifting the slowness of one request onto later ones!]

Configuration

The gem offers a few configuration options:

MaybeLater.config do |config|
  # Will be called if a block passed to MaybeLater.run raises an error
  config.on_error = ->(error) {
    # e.g. Honeybadger.notify(error)
  }

  # Will run after each `MaybeLater.run {}` block, even if it errors
  config.after_each = -> {}

  # By default, tasks will run in a fixed thread pool. To run them in the
  # thread dispatching the HTTP response, set this to true
  config.inline_by_default = false

  # How many threads to allocate to the fixed thread pool (default: 5)
  config.max_threads = 5

  # If set to true, will invoke the after_reply tasks even if the server doesn't
  # provide an array of rack.after_reply array
  config.invoke_even_if_server_is_unsupported = false
end

Help! Why isn't my code running?

If the blocks you pass to MaybeLater.run aren't running, possible explanations include:

  • Because the blocks passed to MaybeLater.run are themselves stored in a thread-local array, if you invoke MaybeLater.run from a thread that isn't handling with a Rack request, the block will never run
  • If your Rack server doesn't support rack.after_reply, the blocks will never run
  • If the block is running and raising an error, you'll only know about it if you register a MaybeLater.config.on_error handler

Acknowledgement

The idea for this gem was triggered by this tweet in reply to this question. Also, many thanks to Matthew Draper for answering a bunch of questions I had while implementing this.

Code of Conduct

This project follows Test Double's code of conduct for all community interactions, including (but not limited to) one-on-one communications, public posts/comments, code reviews, pull requests, and GitHub issues. If violations occur, Test Double will take any action they deem appropriate for the infraction, up to and including blocking a user from the organization's repositories.

maybe_later's People

Contributors

searls avatar

Stargazers

Chris Watkins avatar Andreas Haller avatar Dmitry Makeev avatar Pavel Davydov avatar nicholas a. evans avatar Dario Castañé avatar Anton Katunin avatar Mark Perkins avatar Takafumi ONAKA avatar Tim Krins avatar Bruno Prieto avatar Simon George avatar Yudai Takada avatar Jose Lloret avatar Jose Luis Salas avatar Javier Casal Ruiz avatar Luis Belloch avatar Jorge Barnaby avatar Luc Castera avatar bigint avatar Robert Audi avatar Eliot Sykes avatar Aaron Roh avatar Naoya Ueda avatar Ryo S. avatar Pablo Crivella avatar Chris Fung avatar JP Camara avatar Ryan Buckley avatar Benjamin Klotz avatar Rada Bogdan avatar Dawa Ometto avatar  avatar Sébastien Puyet avatar Peter Shih avatar Gabriel Fontoura Dos Santos avatar Ed Pérez avatar Robin avatar Buts Johan avatar  avatar Alan avatar Odin avatar Ahmed A. Ibrahim avatar Aleksander avatar misoobu avatar Alberto Rocha avatar Bart Kamphorst avatar Yaro Shm avatar Masato Ohba avatar Bertra[N]d Gauriat avatar Josh avatar Andrei Kaleshka avatar Phil Pirozhkov avatar MingyuanQin avatar Sergey Fedorov avatar Nikita avatar Richard Huang avatar Jaryl Sim avatar Jason Weathered avatar Dick Davis avatar Christos Zisopoulos avatar Joshua Priddle avatar Glauco Custódio avatar Ismael Celis avatar Jeb Coleman avatar Desmond Naranjo avatar Gray Kemmey avatar Alessandro Stein avatar Yohei Yasukawa avatar Daniel Puglisi avatar Aurel Branzeanu avatar Victor avatar Robin van der Vleuten avatar Jay Caines-Gooby avatar Franz Liedke avatar Damir M avatar Junya Ogura avatar Bob Maerten avatar Clément Joubert avatar Nathan Donato avatar acrewdson avatar Diogo avatar Patrik Ragnarsson avatar Dean Perry avatar Yuan-Hong Zeng avatar Juanito Fatas avatar Rowan avatar Zach Ahn avatar Tobias Feistmantl avatar Adrian Setyadi avatar Hoa Nguyen avatar Andy Waite avatar kimihito avatar Thomas Hutterer avatar 楊竑昕 avatar Oleksii Kuznietsov avatar Philip Lambok avatar Tim Riley avatar Karl Entwistle avatar Marco Roth avatar

Watchers

Todd Kaufman avatar Ross Brandes avatar James Cloos avatar Aurel Branzeanu avatar Christine McCallum-Randalls avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.