Firebase cloud messaging 如何使Sidekiq在响应头之后重试?

Firebase cloud messaging 如何使Sidekiq在响应头之后重试?,firebase-cloud-messaging,sidekiq,Firebase Cloud Messaging,Sidekiq,我正在使用Sidekiq尝试通过Firebase云消息FCM发送推送通知。FCM需要使用它的服务器提供两种功能: 指数退避 在500响应中执行Retry After标头 我们可以通过Sidekiq免费获得指数退避,但我不确定如何告诉它延迟重试,直到至少在标题中指定的时间 下面我有一个骇人的解决方案,我让工作人员在我起床之前睡觉,但重试逻辑似乎应该存在于Sidekiq中。我是否可以告诉Sidekiq头的Retry After值,这样它就可以做正确的事情 class SendPushNotifica

我正在使用Sidekiq尝试通过Firebase云消息FCM发送推送通知。FCM需要使用它的服务器提供两种功能:

指数退避 在500响应中执行Retry After标头 我们可以通过Sidekiq免费获得指数退避,但我不确定如何告诉它延迟重试,直到至少在标题中指定的时间

下面我有一个骇人的解决方案,我让工作人员在我起床之前睡觉,但重试逻辑似乎应该存在于Sidekiq中。我是否可以告诉Sidekiq头的Retry After值,这样它就可以做正确的事情

class SendPushNotification
  include Sidekiq::Worker
  sidekiq_options queue: :low

  def perform(user_id)
    notification = { body: 'hello world' }
    user = User.find(user_id)
    fcm_token = user.try(:fcm_token) || ENV['FCM_TOKEN']

    uri = URI('https://fcm.googleapis.com/fcm/send')

    http = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true)

    req = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json',
                                   'Authorization' => "key=#{ENV['FCM_API_KEY']}")

    req.body = {
      badge: 0,                      # badge is removed when set to zero
      click_action: 'click',         # string
      collapse_key: 'Handshake',     # collapse multiple messages under this header
      content_available: true,       # wake inactive app
      data: nil,
      registration_ids: [fcm_token], # fcm device tokens
      notification: notification,
      mutable_content: true,         # iOS 10 feature
      priority: 'high',              # high or low (corresponds to 5 and 10 in apns)
      subtitle: nil,
      time_to_live: 2419200,         # max and default for FCM
      dry_run: false                # message is not sent when set to true
    }.to_json

    res =  http.request(req)

    case res
    when Net::HTTPOK
      true
    when Net::HTTPUnauthorized
      raise 'Unauthorized'
    when Net::HTTPBadRequest
      raise "BadRequest: #{res.body}"
    else
      if res.header['Retry-After']
        # this seems like a hacky solution
        sleep res.header['Retry-After']
      end
      raise 'Remote Server Error'
    end
  end
end

不要使用Sidekiq内置的重试功能。计划一个与当前作业相同的新作业,以便在这么多秒内运行

 self.class.perform_in(res.header['Retry-After'].to_i, user_id)

谢谢你的回答,这是一个很好的工作平台:这个解决方案有一个很好的副作用,就是不会用谷歌方面的错误来填充BugSnag。重试用于异常情况和处理代码中的错误。这是一个正常的代码路径,在这个意义上并不例外。你确实有一个缺点,这个循环可能永远执行,这里的重试没有限制。我不知道如何优雅地处理边缘的情况。非常真实的关于:无限循环。如果谷歌不发回标题,我会转而使用Sidekiq的重试策略。如果他们真的一直发送它:''_ツ_/¯