firebase - 使用 firebase-admin SDK for go 重试失败的 FCM 消息
问题描述
我正在为 Go 使用最新版本的 firebase-admin-sdk,以便我可以使用 FCM 发送推送通知。我已经构建了一个客户端,并且能够使用该SendMultiCast()
方法成功发送/接收通知。
Firebase 团队建议使用指数退避方法实施重试,以处理失败的请求。我已经设置了在旧 FCM 库中使用过的回退。问题是我不确定我应该在重试逻辑中处理哪种类型的错误以重播请求。我相信通常最好只在网络交付问题的情况下这样做。
这是基本的重试...我已经注释掉了其中寻找 net.Errors 的代码,因为管理 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
}
谢谢!
解决方案
br, err := client.SendMulticast(ctx, msg)
if err != nil {
// total failure
}
if br.FailureCount > 0 {
// partial failure
}
您不必在完全失败时重试。SDK 会自动处理。当您的代码看到上述错误时,它已经重试了几次都没有成功,或者该错误根本不符合重试条件。
对于部分失败,该messaging.SendResponse
类型包括一个错误,该错误可以通过messaging
包或新errorutils
包的错误处理函数来确定它是否有资格重试。通常,您只想在messaging.IsUnavailable()
返回 true 的情况下重试。
您还需要确保重试仅发送到在先前尝试中失败的令牌。我在您上面给出的代码中看不到这种逻辑。
推荐阅读
- html - 如何根据占位符文本调整输入字段的宽度?
- javascript - 使用jquery在html表中选择输入元素的值
- logstash - 用于 mysql 日志的 Logstash Grok 模式
- apache - 无法在 Windows 上配置 xampp 服务器
- angular - 动态添加组件Angular 5
- r - 如何找到位于R中不同行的两个日期之间的差异?
- arduino - AT+CIPSTART 错误关闭
- java - Hibernate 到底在哪里使用 HttpURLConnection
- .htaccess - 如何使用 htaccess 重写 url
- bash - 使用变量作为路径删除旧文件