持久任务框架重新排队失败的任务

时间:2018-04-06 12:59:37

标签: azure azure-storage

如何使用"等待外部"代码中持久任务框架的事件功能。以下是示例代码。

listI4

我正在使用ScheduleWithRetry<>在DTF上调度我的任务的上下文方法,但是当代码中发生异常时。上述方法重试 _retryOptions 次。

完成重试后,业务流程状态将标记为失败

我需要一个流程来纠正异常原因后我可以在DTF上恢复我的编排。

我正在查看代码中相关方法的githib代码,但没有成功。

我已经得出两个解决方案:

  1. 调用框架的方法(如果存在),并将业务流程从失败的状态重新排队。
  2. 将编排代码保存在try catch中并在catch部分中实现一个方法 CreateOrchestrationInstanceWithRaisedEventAsync whcih会将业务流程置于保持状态,直到外部事件触发它为止。每当用户(使用某些前端应用程序)将调用外部事件进行恢复时(这意味着用户已进行了导致异常的更正)。
  3. 这些是我的理解,如果上述其中一项是可能的,那么请指导我完成一些技术建议。否则找到一个正确的路径来完成这项任务。

2 个答案:

答案 0 :(得分:1)

为了社区的利益,Salman通过以下方式解决了这个问题:

  

“我通过在执行活动时发生异常的情况下创建子业务流程来解决问题。子业务流程将azure上的事件锁定为挂起状态,并等待引发锁定事件的外部事件,以便父级业务流程恢复活动的过程。如果我们的业务流程即将在azure持久性任务框架上失败,这个过程会有所帮助“

答案 1 :(得分:0)

我已经通过使用" Signal Orchestrations"找到了我的问题的解决方案。取自code from GitHub repository

以下是该问题的解决方案图。

enter image description here

在此图中,在实施解决方案之前,我们只有#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);
    }
}