{"action":"created","issue":{"url":"https://api.github.com/repos/mperham/sidekiq/issues/2529","labels_url":"https://api.github.com/repos/mperham/sidekiq/issues/2529/labels{/name}","comments_url":"https://api.github.com/repos/mperham/sidekiq/issues/2529/comments","events_url":"https://api.github.com/repos/mperham/sidekiq/issues/2529/events","html_url":"https://github.com/mperham/sidekiq/issues/2529","id":104522696,"number":2529,"title":"sidekiq_retries_exhausted with extracted (not inline) block","user":{"login":"mooreniemi","id":1695630,"avatar_url":"https://avatars.githubusercontent.com/u/1695630?v=3","gravatar_id":"","url":"https://api.github.com/users/mooreniemi","html_url":"https://github.com/mooreniemi","followers_url":"https://api.github.com/users/mooreniemi/followers","following_url":"https://api.github.com/users/mooreniemi/following{/other_user}","gists_url":"https://api.github.com/users/mooreniemi/gists{/gist_id}","starred_url":"https://api.github.com/users/mooreniemi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mooreniemi/subscriptions","organizations_url":"https://api.github.com/users/mooreniemi/orgs","repos_url":"https://api.github.com/users/mooreniemi/repos","events_url":"https://api.github.com/users/mooreniemi/events{/privacy}","received_events_url":"https://api.github.com/users/mooreniemi/received_events","type":"User","site_admin":false},"labels":[],"state":"closed","locked":false,"assignee":null,"milestone":null,"comments":2,"created_at":"2015-09-02T16:33:19Z","updated_at":"2015-09-03T14:10:26Z","closed_at":"2015-09-02T20:12:37Z","body":"I don't want this to fall into the bike-shedding area, so feel free to close this if you think it does. I wanted to show you an issue I had and the solution I came up with that I feel \"meh\" about.\r\n\r\n5 or more of my workers have a custom block for `sidekiq_retries_exhausted`, but all the blocks (inline) are the same. So naively I thought to myself, \"ok let's extract them to one place!\"\r\n\r\nHere's the test I came up with to work through that:\r\n\r\n```\r\nrequire 'rspec'\r\nrequire 'sidekiq_extensions'\r\nrequire 'support/dummy_worker'\r\nrequire 'pry'\r\n#require 'spec_helper'\r\n\r\ndescribe SidekiqExtensions do\r\n  let(:msg) do\r\n    {\r\n      'class' => 'DummyClass',\r\n      'args' => '1,2,3',\r\n      'error_message' => 'StandardError'\r\n    }\r\n  end\r\n  let(:worker) { RetryWorker.new }\r\n  it 'works with #sidekiq_retries_exhausted' do\r\n    expect(Sidekiq).to receive_message_chain(:logger, :warn).\r\n      with(\"Failed DummyClass with 1,2,3: StandardError\")\r\n    worker.sidekiq_retries_exhausted_block.call(msg)\r\n  end\r\nend\r\n```\r\n\r\nNothing unusual in the worker except my attempt at in-lining:\r\n```\r\nrequire 'sidekiq_extensions'\r\nclass RetryWorker\r\n  include Sidekiq::Worker\r\n  include SidekiqExtensions\r\n  sidekiq_retries_exhausted &:send_to_rails_logger\r\nend\r\n```\r\n\r\nWhich is defined over here:\r\n```\r\nrequire 'sidekiq'\r\nmodule SidekiqExtensions\r\n  def send_to_rails_logger(msg)\r\n    Sidekiq.logger.warn \"Failed #{msg['class']} with #{msg['args']}: #{msg['error_message']}\"\r\n  end\r\nend\r\n```\r\n\r\nConfusingly (to me), when I ran the spec I see:\r\n```\r\nrspec spec/lib/sidekiq_extensions_spec.rb\r\n\r\n  1) SidekiqExtensions works with #sidekiq_retries_exhausted\r\n     Failure/Error: worker.sidekiq_retries_exhausted_block.call(msg)\r\n     NoMethodError:\r\n       undefined method `send_to_rails_logger' for #<Hash:0x62d89480>\r\n     # ./spec/lib/sidekiq_extensions_spec.rb:19:in `(root)'\r\n\r\n\r\nFailures:\r\n\r\n  1) SidekiqExtensions works with #sidekiq_retries_exhausted\r\n     Failure/Error: worker.sidekiq_retries_exhausted_block.call(msg)\r\n     NoMethodError:\r\n       undefined method `send_to_rails_logger' for #<Hash:0x62d89480>\r\n     # ./spec/lib/sidekiq_extensions_spec.rb:19:in `(root)'\r\n\r\nFinished in 0.019 seconds (files took 1.17 seconds to load)\r\n1 example, 1 failure\r\n```\r\n\r\nUnless I change the test to explicitly give the receiver in (`worker.sidekiq_retries_exhausted_block.call(worker, msg)`), it uses msg as the receiver.\r\n\r\nOf course, after some thought I realize, \"ohh hmm, `&:` will call `to_proc` which expects `obj` as its first argument\" so I'll either see `ArgumentError: no receiver given` or Hash being used as the receiver depending on how I do the call.\r\n\r\nSo, dutifully, I restructure to make use of methods instead of procs:\r\n\r\n```\r\nrequire 'sidekiq_extensions'\r\nclass ExhaustedWorker\r\n  include Sidekiq::Worker\r\n  extend SidekiqExtensions\r\n  sidekiq_retries_exhausted &method(:send_to_rails_logger)\r\nend\r\n```\r\n\r\nAnd it works. :smile: \r\n\r\nBut this seems kinda weird to me. I wondered if you could think of a different solution that'd enable me to extract all these logging calls into a single module/class/whatever."},"comment":{"url":"https://api.github.com/repos/mperham/sidekiq/issues/comments/137461741","html_url":"https://github.com/mperham/sidekiq/issues/2529#issuecomment-137461741","issue_url":"https://api.github.com/repos/mperham/sidekiq/issues/2529","id":137461741,"user":{"login":"mooreniemi","id":1695630,"avatar_url":"https://avatars.githubusercontent.com/u/1695630?v=3","gravatar_id":"","url":"https://api.github.com/users/mooreniemi","html_url":"https://github.com/mooreniemi","followers_url":"https://api.github.com/users/mooreniemi/followers","following_url":"https://api.github.com/users/mooreniemi/following{/other_user}","gists_url":"https://api.github.com/users/mooreniemi/gists{/gist_id}","starred_url":"https://api.github.com/users/mooreniemi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mooreniemi/subscriptions","organizations_url":"https://api.github.com/users/mooreniemi/orgs","repos_url":"https://api.github.com/users/mooreniemi/repos","events_url":"https://api.github.com/users/mooreniemi/events{/privacy}","received_events_url":"https://api.github.com/users/mooreniemi/received_events","type":"User","site_admin":false},"created_at":"2015-09-03T14:10:26Z","updated_at":"2015-09-03T14:10:26Z","body":"Perhaps may want to document that somewhere then? Save someone else the confusion. Thanks again!"}}