使用firebase-admin SDK重试失败的FCM消息

时间:2020-10-01 17:25:12

标签: firebase go firebase-cloud-messaging firebase-admin

我正在为Go使用最新版本的firebase-admin-sdk,以便可以使用FCM发送推送通知。我已经建立了一个客户端,并且能够使用SendMultiCast()方法成功发送/接收通知。

Firebase团队建议使用指数补偿方法实施重试以处理失败的请求。我设置了一个在较旧的FCM库中使用过的备用项。问题是我不确定在重试逻辑中应该处理哪种类型的错误以重播请求。我认为通常只在出现网络交付问题时才这样做。

这是基本的重试方法...我注释掉了其中的代码以寻找net.Errors,因为它似乎不像admin SDK那样返回。我知道SendMultiCast()方法返回一个错误和一个BatchResponse。错误响应是我应该重试的还是在BatchResponse中?我似乎在批处理响应中找不到要重试的内容。

const (
    minBackoff = 100 * time.Millisecond
    maxBackoff = 1 * time.Minute
)

func retry(fn func() error, attempts int) error {
    var attempt int
    for {
        err := fn()
        log.Println("attempt to send")
        if err == nil {
            return nil
        }
        
        // This is what has worked in past libs since I could expect 
        // net.errors signifying a timeout or some sort of http issue that would
        // require a retry
        // if tErr, ok := err.(net.Error); !ok || !tErr.Temporary() {
        //   return err
        // }

        attempt++
        backoff := minBackoff * time.Duration(attempt*attempt)

        if attempt > attempts || backoff > maxBackoff {
            return err
        }

        time.Sleep(backoff)
    }
}

下面是我尝试使用重试方式的摘要...

func (c *Client) Send(ctx context.Context, msg *messaging.MulticastMessage) (*FCMv1Response, error) {
    res := new(FCMv1Response)
    err := retry(func() error {
        ctx, cancel := context.WithTimeout(ctx, DefaultTimeout)
        defer cancel()
        var er error
        res.FailedTokens, er = c.sendMulticastMessage(ctx, msg)
        return er
    }, RetryAttempts)

    if err != nil {
        c.logger.Error("errorSendingLLUNotification", zap.Error(err))
        return nil, err
    }
    return res, nil

}

func (c *Client) sendMulticastMessage(ctx context.Context, msg *messaging.MulticastMessage) ([]string, error) {
    br, err := c.msg.SendMulticast(ctx, msg)
    if err != nil {
        return nil, err
    }

    var failedTokens []string
    if br.FailureCount > 0 {
        for idx, resp := range br.Responses {
            if !resp.Success {
                // The order of responses corresponds to the order of the registration tokens.
                failedTokens = append(failedTokens, msg.Tokens[idx])
            }
        }
    }
    return failedTokens, nil
}

谢谢!

1 个答案:

答案 0 :(得分:1)

DRAWITEMSTRUCT

您不必重试全部失败。 SDK会自动处理。在您的代码看到上述错误时,它已经被重试了几次而没有成功,或者该错误根本没有资格重试。

对于部分故障,messaging.SendResponse类型包含一个错误,可以通过dwItemData程序包或新的MENUITEMINFO程序包的错误处理功能传递该错误,以确定是否可以重试。通常,您只想在messaging.IsUnavailable()返回true的情况下重试。

您还需要确保重试仅发送到先前尝试中失败的令牌。在您上面提供的代码中,我看不到这种逻辑。