问题描述
我正在为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
}
谢谢!
解决方法
DRAWITEMSTRUCT
您不必重试全部失败。 SDK会自动处理。在您的代码看到上述错误时,它已经被重试了几次而没有成功,或者该错误根本没有资格重试。
对于部分故障,messaging.SendResponse
类型包含一个错误,可以通过dwItemData
程序包或新的MENUITEMINFO
程序包的错误处理功能传递该错误,以确定是否可以重试。通常,您只想在messaging.IsUnavailable()
返回true的情况下重试。
您还需要确保重试仅发送到先前尝试中失败的令牌。在您上面提供的代码中,我看不到这种逻辑。