如何使用"等待外部"代码中持久任务框架的事件功能。以下是示例代码。
listI4
我正在使用ScheduleWithRetry<>在DTF上调度我的任务的上下文方法,但是当代码中发生异常时。上述方法重试 _retryOptions 次。
完成重试后,业务流程状态将标记为失败。
我需要一个流程来纠正异常原因后我可以在DTF上恢复我的编排。
我正在查看代码中相关方法的githib代码,但没有成功。
我已经得出两个解决方案:
这些是我的理解,如果上述其中一项是可能的,那么请指导我完成一些技术建议。否则找到一个正确的路径来完成这项任务。
答案 0 :(得分:1)
为了社区的利益,Salman通过以下方式解决了这个问题:
“我通过在执行活动时发生异常的情况下创建子业务流程来解决问题。子业务流程将azure上的事件锁定为挂起状态,并等待引发锁定事件的外部事件,以便父级业务流程恢复活动的过程。如果我们的业务流程即将在azure持久性任务框架上失败,这个过程会有所帮助“
答案 1 :(得分:0)
我已经通过使用" Signal Orchestrations"找到了我的问题的解决方案。取自code from GitHub repository。
以下是该问题的解决方案图。
在此图中,在实施解决方案之前,我们只有#34; Process Activity"实际上执行活动。
Azure存储表用于存储instanceId和ActivityName的乘数值。为什么我们实施这个将在以后明确。
监控网站是用户可以重新排队/重试业务流程活动以执行的平台。
现在我们有一个前步骤和一个后步骤。
<强> 1。获取重试选项(前置步骤) 此方法基本上设置 RetryOptions 实例值的值。
private RetryOptions ModifyMaxRetires(OrchestrationContext context, string activityName)
{
var failedInstance =
_azureStorageFailedOrchestrationTasks.GetSingleEntity(context.OrchestrationInstance.InstanceId,
activityName);
var configuration = Container.GetInstance<IConfigurationManager>();
if (failedInstance.Result == null)
{
return new RetryOptions(TimeSpan.FromSeconds(configuration.OrderTaskFailureWaitInSeconds),
configuration.OrderTaskMaxRetries);
}
var multiplier = ((FailedOrchestrationEntity)failedInstance.Result).Multiplier;
return new RetryOptions(TimeSpan.FromSeconds(configuration.OrderTaskFailureWaitInSeconds),
configuration.OrderTaskMaxRetries * multiplier);
}
如果我们的azure存储表中有任何针对 instanceId 和 ActivityName 的条目,我们会从表中获取乘数值并更新< strong> RetryOption 实例创建。否则我们使用来自配置的默认重试值。
,然后: 我们使用计划的重试次数处理活动(如果活动在任何情况下都失败)。
<强> 2。处理例外(后步骤) 即使在 RetryOption 实例中为活动设置的重试次数后,活动也无法完成,此方法基本上处理异常。
private async Task HandleExceptionForSignal(OrchestrationContext context, Exception exception, string activityName)
{
var failedInstance = _azureStorageFailedOrchestrationTasks.GetSingleEntity(context.OrchestrationInstance.InstanceId, activityName);
if (failedInstance.Result != null)
{
_azureStorageFailedOrchestrationTasks.UpdateSingleEntity(context.OrchestrationInstance.InstanceId, activityName, ((FailedOrchestrationEntity)failedInstance.Result).Multiplier + 1);
}
else
{
//const multiplier when first time exception occurs.
const int multiplier = 2;
_azureStorageFailedOrchestrationTasks.InsertActivity(new FailedOrchestrationEntity(context.OrchestrationInstance.InstanceId, activityName)
{
Multiplier = multiplier
});
}
var exceptionInput = new OrderExceptionContext
{
Exception = exception.ToString(),
Message = exception.Message
};
await context.CreateSubOrchestrationInstance<string>(typeof(ProcessFailedOrderOrchestration), $"{context.OrchestrationInstance.InstanceId}_{Guid.NewGuid()}", exceptionInput);
}
上面的代码首先尝试在azure存储中找到instanceID和ActivityName。如果它不存在那么我们只需在azure存储表中为InstanceId和ActivityName添加一个新行,其默认乘数值为2.
稍后我们创建一个新的异常类型实例,用于将异常消息和详细信息发送到子编排(将在监控网站上显示给用户)。子编排等待用户针对子编排的InstanceId触发的外部事件。
每当从监控网站触发时,子业务流程将结束并返回再次启动父业务流程。但是这次,当再次调用Pre-Step活动时,它会在带有乘数的azure存储表中找到该条目。这意味着重试选项在与默认重试选项相乘后会更新。
通过这种方式,我们可以继续我们的编排并防止它们失败。
以下是子编排类。
internal class ProcessFailedOrderOrchestration : TaskOrchestration<string, OrderExceptionContext>
{
private TaskCompletionSource<string> _resumeHandle;
public override async Task<string> RunTask(OrchestrationContext context, OrderExceptionContext input)
{
await WaitForSignal();
return "Completed";
}
private async Task<string> WaitForSignal()
{
_resumeHandle = new TaskCompletionSource<string>();
var data = await _resumeHandle.Task;
_resumeHandle = null;
return data;
}
public override void OnEvent(OrchestrationContext context, string name, string input)
{
_resumeHandle?.SetResult(input);
}
}