【问题标题】:Ruby error handling: Rescuing Exceptions in SubclassesRuby 错误处理:拯救子类中的异常
【发布时间】:2017-01-30 00:03:03
【问题描述】:

我有一个 Adapter 类的集合,这些类连接到各种 API 等等。以下是每个适配器如何设置的简单通用示例:

class AmazonAdapter
    include Sidekiq::Worker
    def perform(id)
        get_results_from_api(id)
    end
end

class WalmartAdapter
    include Sidekiq::Worker
    def perform(id)
        get_results_from_api(id)
    end
end

所以一般来说,通过调用AmazonAdapter.new(500),它将连接到 API 并根据您作为 ID 传入的内容返回结果。这都是 Sidekiq 收集过程的一部分,并作为后台作业运行,因此当出现问题时它不一定会抛出明显的异常或错误来提醒我。

我想使用 AirBrake 的通知系统在 API 未正确连接或抛出任何其他错误时通知我,但不会停止收集过程或 sidekiq。我希望将错误处理和通知系统纳入主流。

我的一些想法是创建一个子类可以继承的 ParentClass,看起来类似于:

class Adapter
    include Sidekiq::Worker
    def perform(id)
        begin
            #execute subclass perform method
        rescue Exception => e
            Airbrake.notify(e)
        end
    end
end

但我不确定解决此问题的最佳方法。我真的可以在这方面使用一些建议或帮助,谢谢!

【问题讨论】:

    标签: ruby inheritance error-handling custom-error-handling airbrake


    【解决方案1】:

    Sidekiq 中存在一个瓶颈,它基本上执行所有操作:Sidekiq::Processor#execute_job,它接收两个参数 (worker, cloned_args) 并随后调用 worker.perform(*cloned_args)。所以,为了你的目的,我会在模块前面加上:

    Sidekiq::Processor.prepend(Module.new do
      def execute_job(worker, cloned_args)
        super # CALL ORIGINAL
      rescue => e # NEVER RESCUE FROM EXCEPTION!!!
        Airbrake.notify(e) # NOTIFY
        raise e # RE-RAISE SO SIDEKIQ DOES HIS JOB
      end
    end)
    

    在你的第一份工作之前调用它,你就完成了:在 Sidekiq 调用工作人员期间发生的所有错误现在都被空气制动了。

    希望对你有帮助。

    【讨论】:

    • 谢谢!我会试试这个。我知道您永远不想挽救异常。但我正在运行一个做一件事的应用程序,而那一件事是通过管道系统(用光纤/线程实现)收集数据。一旦一名工人被解雇,它就会同时解雇数百个工作,并且由于它是一个 sidekiq 执行,我不会收到没有发生收集的通知。我不一定希望它抛出异常,因为我想让工作人员继续运行。当您说“所以 sidekiq 完成了他的工作”时,您的意思是让他继续重试工作吗?
    • ‘当你说“所以 sidekiq 完成了他的工作”时,你的意思是让他继续重试工作吗?——是的。 Sidekiq 将根据Worker 实现中指定的retry: true|false 参数重试或静默跳过重试。顺便说一句,拯救Exception 没有多大意义,因为OutOfMemory 和其他Exception 通常无法处理。
    【解决方案2】:

    我使用类似的构造来提醒我某些 chron 作业中的失败并 ping 一个松弛通道,但好的部分是它不需要继承!一个天真的版本看起来像这样:

    class AirbrakeNotifier
      def safe_run
        yield
      rescue StandardError => e
        log_error(e)
        raise e
      end
    
      private
    
      def log_error(e)
        # do your logging here
      end
    end
    

    然后你的工人看起来像这样:

    class AmazonAdapter
      include Sidekiq::Worker
    
      def perform(id)
        AirbrakeNotifier.new.safe_run { get_results_from_api(id) }
      end
    end
    

    这为您提供了更大的灵活性,可以根据您想要的每个类、每个进程或您能想到的不同方式配置日志记录!

    【讨论】:

    • 嘿德文!好久不见,希望一切安好!太棒了,我要研究一下!
    猜你喜欢
    • 2013-06-28
    • 1970-01-01
    • 2011-06-15
    • 2018-11-27
    • 2013-11-27
    • 2020-12-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多