Bg
Non-blocking ActiveRecord method invocation
This library allows you to invoke ActiveRecord instance methods in the background.
-
Bg::Asyncable
uses concurrent-ruby to execute methods in a different thread -
Bg::Deferrable
uses ActiveJob to execute methods in a background process
Quickstart
Setup
class User < ApplicationRecord
include Bg::Asyncable::Behavior # uses concurrent-ruby
include Bg::Deferrable::Behavior # uses ActiveJob
end
Usage
user = User.find(params[:id])
# blocking in-process
user.do_hard_work
# non-blocking in-process separate thread
user.async.do_hard_work
# non-blocking out-of-process background job
user.defer.do_hard_work
user.defer(queue: :low, wait: 5.minutes).do_hard_work
Deferrable
Bg::Deferrable
leverages GlobalID::Identification to marshal ActiveRecord instances across process boundaries.
This means that state is not shared between the main process & the process actually executing the method.
- Do not depend on lexically scoped bindings when invoking methods.
-
Do not pass unmarshallable types as arguments.
Bg::Deferrable
will prepare arguments for enqueuing, but best practice is to follow Sidekiq's simple parameters rule.
Examples
Good
user = User.find(params[:id])
user.defer.do_hard_work 1, true, "foo"
Bad
user = User.find(params[:id])
# in memory changes will not be available in Bg::Deferrable invoked methods
user.name = "new value"
# args may not marshal properly
user.defer.do_hard_work :foo, Time.now, instance_of_complex_type
user.defer.do_hard_work do
# blocks are not supported
end
Asyncable
Bg::Asyncable
disallows invoking methods that take blocks as an argument.
- Important: It's your responsibility to protect shared data between threads
Examples
Good
user = User.find(params[:id])
user.name = "new value"
user.async.do_hard_work 1, true, "foo"
user.async.do_hard_work :foo, Time.now, instance_of_complex_type
Bad
user = User.find(params[:id])
user.async.do_hard_work do
# blocks are not supported
end