如何使Sidekiq尊重Retry-After响应头?

时间:2017-09-23 17:39:42

标签: firebase-cloud-messaging sidekiq

我正在使用Sidekiq尝试通过Firebase云消息传递(FCM)发送推送通知。 FCM需要使用它的服务器中的两件事:

  1. 指数退避
  2. 尊重500响应中的Retry-After标头
  3. https://firebase.google.com/docs/cloud-messaging/http-server-ref#table4

    我们可以免费获得Sidekiq的指数退避,但我不确定如何告诉它延迟重试,直到至少在标题中指定的时间。

    我在下面有一个hacky解决方案,我在sleep之前创建了工作raise,但似乎重试逻辑应该存在于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
    

1 个答案:

答案 0 :(得分:1)

请勿使用Sidekiq的内置重试。安排一个与当前工作相同的新工作,在很多秒内运行。

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