发布日期: 2026-06-15
版本号: v1.17.10

Dapr 1.17.10 版本修复了一个关键问题,该问题导致在对发布-订阅组件的出站策略配置重试策略时,其中的 matching(错误码匹配条件)被完全忽略。具体表现为,当使用 PublishBulkPublish API 发布消息时,所有错误都会被重试至最大次数,无论其是否属于可重试错误,导致终端错误也被不必要地重试。根本原因在于发布路径未将组件错误包装为可被重试策略识别的特定类型,从而绕过了错误码检查。本次修复通过在发布路径中包装符合 gRPC 状态码的错误,确保匹配条件生效,使得重试行为能够根据配置的错误码正确执行。

更新内容 (中文)

Dapr 1.17.10

本次更新包含以下错误修复:

弹性重试 matching 在发布/订阅发布路径中被忽略

问题描述

针对发布/订阅组件出站策略配置的弹性重试策略中的 matchinghttpStatusCodes / gRPCStatusCodes)对发布操作无效。
所有 Publish / BulkPublish 错误均会按照 maxRetries 指定的次数进行重试,而不考虑配置的状态码,导致非重试型(终止性)错误被无效重试,配置的 matching 被静默忽略。

影响范围

所有设置了 Resiliency 配置,且在针对发布/订阅组件的 outbound 重试策略中配置了 matching 的部署均受影响。

可见症状包括:

  • 明显的终止性发布错误(例如无效的主题或未授权的请求)被重试 maxRetries 次,而非快速失败。
  • matching.httpStatusCodes / matching.gRPCStatusCodes 中列出的状态码对哪些发布错误会被重试没有任何影响。

根本原因

pkg/resiliency/policy.go 中的重试运行器仅在操作错误为 resiliency.CodeError 时才会查询配置的状态码。
其他所有策略运行器——服务调用、gRPC代理、输出绑定和入站订阅者传递——在将错误交给运行器之前都会构造一个 CodeError,但组件出站发布路径却直接返回了 broker 的原始错误。
因此发布错误从未被识别为 CodeError,配置的状态码从未被查询,它作为普通的可重试错误进入了运行器。

解决方案

现在,PublishBulkPublish 路径在组件错误携带 gRPC 状态(通过 status.FromError)时,会将其包装在 resiliency.CodeError 中,与其他策略运行器保持一致。
不携带状态的错误将原样返回,并完全按照之前的方式继续重试,因此除非配置了重试 matching,否则行为不变。

这是修复的运行时部分;components-contrib 中的发布/订阅组件在发布错误时会发出 gRPC 状态码,以便运行时可以将其分类为可重试或终止性错误。

更新内容 (原始)

Dapr 1.17.10

This update contains the following bug fix:

Resiliency retry matching is ignored on the pubsub publish path

Problem

A resiliency retry policy that configures matching (httpStatusCodes / gRPCStatusCodes) on a pubsub component’s outbound policy has no effect on publish. Every Publish / BulkPublish error is retried up to maxRetries regardless of the configured codes, so non-retriable (terminal) errors are retried wastefully and the configured matching is silently ignored.

Impact

Any deployment with a Resiliency configuration that sets matching on a retry policy targeting a pubsub component’s outbound retry is affected.

Visible symptoms include:

  • A clearly terminal publish error (for example an invalid topic or an unauthorized request) is retried up to maxRetries instead of failing fast.
  • The status codes listed in matching.httpStatusCodes / matching.gRPCStatusCodes have no effect on which publish errors are retried.

Root Cause

The retry runner in pkg/resiliency/policy.go only consults the configured codes when the operation error is a resiliency.CodeError. Every other policy runner — service invocation, the gRPC proxy, output bindings, and inbound subscriber delivery — constructs a CodeError before handing the error to the runner, but the component-outbound publish path returned the broker’s plain error verbatim. As a result the publish error was never recognized as a CodeError, the configured codes were never consulted, and it fell through to the runner as an ordinary retryable error.

Solution

The Publish and BulkPublish paths now wrap the component error in a resiliency.CodeError when it carries a gRPC status (via status.FromError), mirroring the other policy runners. Errors that do not carry a status are returned unchanged and keep retrying exactly as before, so behavior is unchanged unless retry matching is configured.

This is the runtime half of the fix; pubsub components in components-contrib emit gRPC status codes on publish errors so the runtime can classify them as retriable or terminal.

下载链接