-
Notifications
You must be signed in to change notification settings - Fork 2.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Optional extension loading #1778
Optional extension loading #1778
Conversation
I tested this by running the following commands in the Sidekiq repository:
|
I like this but I'd prefer a global method to be called, e.g. Sidekiq.disable_extensions! instead of a special require. |
@mperham I did some experimenting with a global method or as a configuration option, but there's definitely some friction. Consider the following, simplified example extracted from require 'helper'
require 'sidekiq' # Mark 1
require 'active_record'
require 'action_mailer'
require 'sidekiq/extensions/action_mailer'
require 'sidekiq/extensions/active_record'
require 'sidekiq/rails'
Sidekiq.hook_rails! # This would be impliciltly called in a real Rails app
# Mark 2
class SomeClass
def self.doit(arg)
end
end
SomeClass.delay.doit(Date.today) # Mark 3 Ideally, we'd like to be able to put a call to Since no other Sidekiq code executes between The simpliest, but potential very impactful, option I tried involved overriding One problem is the tests won't pass if run together. To get it to work, the two disabling extensions related tests must be run in a separate process since there's interaction with what code is loaded. A couple other options for consideration:
def delay(*args)
if Sidekiq.extensions_disabled?
if defined?(super)
super(*args)
else
raise NoMethodError.new("undefined method `delay' for #{self.inspect}:#{self.class}")
end
else
sidekiq_delay(*args)
end
end (This could easily be extracted into its own macro to replace Any suggestions or feedback? |
The problem is (2) is that people don't want #delay registered as a method in the first place. Someone else offered (1) a few months ago; I declined it because it was messy. Could we register the delay methods in a :startup event which is executed after Rails initializers are run? An initializer could call |
@mperham What about https://github.com/hundredwatt/sidekiq/commit/17d134b577121ceabea48f192e6f67688afecceb, specifically: https://github.com/hundredwatt/sidekiq/blob/17d134b577121ceabea48f192e6f67688afecceb/lib/sidekiq/extensions/object.rb? I decided to put the Seems like the ideal approach might be: For Rails applications: use your approach For non-Rails applications: Don't load the extensions by default Other than that, I don't see a way to have the extensions load by default AND be disable-able without meta-programming / doing what I did in my example. |
I think that's overly complicated. If we just activate delay in the startup hook, it should be really clean. Non-rails apps are using the |
Shoot, I knew I was forgetting something. #delay is relevant in the client and there's no startup hook in the client. |
I'm wondering if the right thing is to make #delay opt-in in Sidekiq 4.0. |
An initializer approach for Rails would still work for the client. For non Rails app, we could load the extensions immediately. That way, we wouldn't break the 3.x API. Something like: require 'sidekiq/extensions/class_methods'
require 'sidekiq/extensions/action_mailer'
require 'sidekiq/extensions/active_record'
if defined?(::Rails::Engine)
require 'sidekiq/rails'
else
# immediately load extensions
end In general, I agree with @dhh's comment that the Should I look into the above approach for now? |
I like it. Go for it and let's see what you come up with. |
Ok, will do next week |
…estart Prevent exceptions caused by Sidekiq::Shutdown from causing jobs to be retried
Just realized there's |
I made this little sample to test that approach in Ruby 2.0. Seems to work fine and doesn't interfere with other inherited modules: class Base
#def bar
# p "Base's method"
#end
end
module A
def bar
p "A's method"
end
end
module B
module Ext
def foo
p "B's method"
end
alias :bar :foo
end
end
Base.send(:include, A)
Base.send(:include, B::Ext)
Base.new.bar #=> "B's method"
B::Ext.module_eval do
remove_method :bar
end
Base.new.bar #=> "A's method" |
@mperham leveraging That would complete the approach we described above. Thoughts? |
Looks pretty slick. Would you update the Delay Extensions wiki page with a blurb on this? |
Thought of an edge case, am going to fix it and then I will update the wiki |
Nevermind, edge case is actually a benefit, will describe in wiki |
@mperham wiki updated: https://github.com/mperham/sidekiq/wiki/Delayed-extensions. Thanks for your feedback, this was an interesting exploration! |
Relates to #1684
The developer can load Sidekiq without the extensions injected by requiring
sidekiq/no_extensions
instead ofsidekiq
.