1

i am working on a rails app and currently we are migrating to jruby. we currently have over 10 after callbacks on the one of our models and this is blocking the response for a long time.

after_update :sync
after_update :send
after_create :add
after_create :add
after_create :send
after_update :track!
after_create :track!
after_create :send_welcome_email
after_create :track
after_update :send
after_update :set_is_active!
after_update :set_
after_create :apply
after_update :apply
after_update :clear
after_create :mark

i need to wrap/override activerecord's after callbacks (after_save, after_update) to run them asynchronously using concurrent-ruby to not block the response but i don't know how to do that the right way.

what i want to do is something like that

require 'concurrent'
class ApplicationRecord < ActiveRecord::Base
  def after_update
    Concurrent::Promise.new { super }.exec
  end
end

i just need to know the right syntax and whether this is the right approach for something like that. would appreciate any suggestions.

fady zohdy
  • 45
  • 1
  • 8
  • are you interested in response talking about sidekiq? – DonPaulie Dec 04 '18 at 13:42
  • i know about sidekiq. i feel concurrent::promise is much cleaner and doesn't need anymore hassle. plus this is the reason we switched to jruby, to be able to use such concurrency libs @DonPaulie – fady zohdy Dec 04 '18 at 14:17

1 Answers1

0

there's no general advice here - one needs to know a bit about the application.

few things to be aware of :

  • sounds like you're in a callback hell, maybe rethink the architecture a bit - slim those models down and/or use observers (to simplify)

  • you certainly can move execution into another thread but after actions should best not depend on each other's state

  • also if those after parts do DB operations be aware of running them outside the 'main' transaction

  • last but not least do not forget to do cleanup - AR connections should be put back to the pool as Rails won't do that for you (as with request threads) unless you explicitly tell it

what to make of it in general would be: if you need to wait for completion and your callbacks need to run in sequence moving them onto another thread will not have much effect. if that is not the case - try it out and maybe think about whether you want all promises running on the same (default) executor or want to explicitly define different ones (e.g. for CPU intensive tasks vs. IO bound ones).

kares
  • 7,076
  • 1
  • 28
  • 38