UiPath Pitfall #3: Expecting Orchestrator to Retry a Business Exception
Your failed queue item never got retried. Or the opposite: the robot hit the same broken item three times in a row. Almost every time, it comes down to which exception type the item failed with. This question shows up on the UiPath Forum every few weeks in one form or another, so it got its own Pitfall of the Week.
你失败的队列项从未被重试。或者恰恰相反:机器人连续三次处理同一个损坏的项目。几乎每次出现这种情况,都归结为该项目失败时所使用的异常类型。这个问题每隔几周就会以某种形式出现在 UiPath 论坛上,因此它成为了本周的“避坑指南”主题。
The mistake: Treating Business and Application exceptions as two labels for the same thing, “failed”. Orchestrator treats them very differently. Application exception + Auto Retry turned on for the queue: Orchestrator retries the item, up to the queue’s max number of retries. Business exception: Orchestrator doesn’t retry it by default. That’s straight from the Set Transaction Status docs. With ErrorType set to Application, the transaction is retried according to the settings in Orchestrator. With Business, it isn’t.
错误之处:将业务异常(Business Exception)和应用程序异常(Application Exception)视为“失败”这一概念的两个标签。Orchestrator 对它们的处理方式截然不同。对于开启了自动重试功能的队列,如果出现应用程序异常,Orchestrator 会重试该项目,直到达到队列设置的最大重试次数。而对于业务异常,Orchestrator 默认不会进行重试。这一点直接出自“设置事务状态”(Set Transaction Status)文档。当错误类型设置为 Application 时,事务会根据 Orchestrator 中的设置进行重试;而设置为 Business 时,则不会。
It bites in two directions: A technical problem thrown as a BusinessRuleException. Say a page timeout or a frozen app ends up in the wrong catch. The item goes straight to Failed and never gets a second chance, even though a retry would probably have worked. A data problem thrown as a plain System.Exception. Missing invoice number, invalid customer ID. The item gets retried, fails the exact same way, and burns runtime. If the failing step is a login with bad credentials, repeated retries can also get the account locked.
这会带来两个方向的困扰:一是将技术问题抛出为 BusinessRuleException。例如,页面超时或应用程序卡死被错误地捕获。该项目会直接进入“失败”状态且永远没有第二次机会,尽管重试很可能奏效。二是将数据问题抛出为普通的 System.Exception。例如缺少发票号码或客户 ID 无效。该项目会被重试,但以同样的方式失败,从而浪费运行时间。如果失败的步骤是使用错误的凭据登录,反复重试还可能导致账户被锁定。
In REFramework, what you throw is the decision. REFramework makes the split for you. In SetTransactionStatus.xaml, anything thrown as BusinessRuleException is marked Business, and everything else is marked Application. So the exception type you throw in Process.xaml decides whether the item gets another shot. A data check in Process.xaml can be as simple as this (VB): If String.IsNullOrWhiteSpace(in_TransactionItem.SpecificContent(“InvoiceNumber”).ToString) Then Throw New BusinessRuleException(“Invoice number is missing”) End If. In Studio you’d normally do this with an If activity and a Throw activity, but the idea is the same.
在 REFramework 中,你抛出的异常决定了后续流程。REFramework 会为你进行区分。在 SetTransactionStatus.xaml 中,任何抛出为 BusinessRuleException 的异常都会被标记为 Business,而其他所有异常都会被标记为 Application。因此,你在 Process.xaml 中抛出的异常类型决定了该项目是否能获得再次处理的机会。在 Process.xaml 中进行数据检查可以像这样简单(VB):If String.IsNullOrWhiteSpace(in_TransactionItem.SpecificContent(“InvoiceNumber”).ToString) Then Throw New BusinessRuleException(“Invoice number is missing”) End If。在 Studio 中,你通常会使用 If 活动和 Throw 活动来实现,但核心逻辑是一样的。
What I do now: Ask one question before throwing: would running this exact item again, unchanged, have a real chance of working? Yes means Application. No (bad or missing data, a business rule the item fails) means BusinessRuleException. Validate input data early in Process.xaml and throw BusinessRuleException with a clear message. That way the reason shows up in the transaction details instead of a stack trace. Handle a shared login failure in the Init state and stop the job, instead of failing every queue item one by one.
我现在这样做:在抛出异常前问一个问题:如果不对该项目做任何修改再次运行,它有真正的成功机会吗?如果是,则使用 Application 异常;如果不是(数据错误或缺失,或违反了业务规则),则使用 BusinessRuleException。在 Process.xaml 中尽早验证输入数据,并抛出带有清晰信息的 BusinessRuleException。这样,失败原因会显示在事务详情中,而不是堆栈跟踪里。在 Init 状态下处理共享登录失败并停止作业,而不是让每个队列项逐一失败。
Let one layer own retries. The note on MaxRetryNumber in the REFramework Config.xlsx says it must be 0 when you’re working with Orchestrator queues. So leave it at 0 and set retries on the queue itself (Edit queue, Auto Retry section). Retry a single flaky step in place. If one step just needs another try right away, wrap only that step in a Retry Scope (Number Of Retries, Retry Interval) instead of failing the whole item.
让一个层级负责重试。REFramework 的 Config.xlsx 中关于 MaxRetryNumber 的注释指出,当使用 Orchestrator 队列时,该值必须为 0。因此,请将其保持为 0,并在队列本身设置重试(编辑队列,自动重试部分)。在原地重试单个不稳定的步骤。如果某个步骤只需要立即再试一次,请仅将该步骤包装在重试范围(Retry Scope,设置重试次数和重试间隔)中,而不是让整个项目失败。