繁体   English   中英

如何重试先前的异步任务

[英]How do I retry an antecedent async task

我有一系列异步调用,其中一些依赖于在开始其他任务之前完成的其他任务。 我想为这些调用设置重试逻辑,因为它们都是对外部资源的调用。 这是我们的原型代码,没有任何异常处理或重试逻辑:(这可以完成工作,但没有任何弹性或错误处理)。 经过相当多的研究,我需要一些帮助,以一种有弹性的方式将它们组合在一起。

Task uploadHdr = null;
Task uploadElig = null;
Task ImportHdrCPA = null;
Task ImportHdrCCRS = null;
Task ImportEligCPA = null;
Task ImportEligCCRS = null;
Task ProcessCPA = null;
Task ProcessCCRS = null;

//Connect to blob storage
CloudStorageAccount storageacc = CloudStorageAccount.Parse("connection string to blob storage");
CloudBlobClient blobClient = storageacc.CreateCloudBlobClient();
CloudBlobContainer container = blobClient.GetContainerReference("ourcontainer");           

//Import Header to Choice PA
using (SqlConnection conCPA = new SqlConnection("connection string for CPA"))
using (SqlConnection conCCRS = new SqlConnection("connection string for CCRS"))
{
    conCPA.Open();
    conCCRS.Open();

    //Upload HDR file
    CloudBlockBlob hdrBlob = container.GetBlockBlobReference("Header.txt");
    FileStream fsHdr = System.IO.File.OpenRead(@"C:\Development\Header.txt");
    uploadHdr = hdrBlob.UploadFromStreamAsync(fsHdr);
    allTasks.Add(uploadHdr);
    Console.WriteLine("Started Header Upload " + stopwatch.Elapsed.ToString());

    //Upload eligibility segment file
    CloudBlockBlob elgBlob = container.GetBlockBlobReference("Detail.txt");
    FileStream fsElig = System.IO.File.OpenRead(@"C:\Development\Detail.txt");
    uploadElig = elgBlob.UploadFromStreamAsync(fsElig);
    allTasks.Add(uploadElig);
    Console.WriteLine("Started Detail Upload " + stopwatch.Elapsed.ToString());

    while (allTasks.Any())
    {
        Task.WhenAny(allTasks.ToArray());

        if (uploadHdr.IsCompletedSuccessfully && ImportHdrCPA == null)
        {
            SqlCommand cmdHdrCPA = new SqlCommand("dbo.spImportHeader", conCPA) { CommandType = CommandType.StoredProcedure, CommandTimeout = 0 };
            cmdHdrCPA.Parameters.Add("@FileName", SqlDbType.VarChar);
            cmdHdrCPA.Parameters["@FileName"].Value = "Header.txt";
            ImportHdrCPA = cmdHdrCPA.ExecuteNonQueryAsync();
            allTasks.Add(ImportHdrCPA);
            Console.WriteLine("Started Header Import 1 " + stopwatch.Elapsed.ToString());
        }

        if (ImportHdrCPA.IsCompletedSuccessfully && ImportHdrCCRS == null)
        {
            SqlCommand cmd = new SqlCommand("dbo.spNCEligibilityImportHeader", conCCRS) { CommandType = CommandType.StoredProcedure, CommandTimeout = 0 };
            cmd.Parameters.Add("@FileName", SqlDbType.VarChar);
            cmd.Parameters["@FileName"].Value = "CSC_NCEligibility_Hdr_i_20191105.txt";
            ImportHdrCCRS = cmd.ExecuteNonQueryAsync();
            allTasks.Add(ImportHdrCCRS);
            Console.WriteLine("Started Header Import 2 " + stopwatch.Elapsed.ToString());
        }

        if(uploadElig.IsCompletedSuccessfully && ImportEligCPA == null)
        {
            SqlCommand cmd = new SqlCommand("dbo.spImportDetail", conCPA) { CommandType = CommandType.StoredProcedure, CommandTimeout = 0 };
            cmd.Parameters.Add("@FileName", SqlDbType.VarChar);
            cmd.Parameters["@FileName"].Value = "Detail.txt";
            ImportEligCPA = cmd.ExecuteNonQueryAsync();
            allTasks.Add(ImportEligCPA);
            Console.WriteLine("Started Detail Import 1 " + stopwatch.Elapsed.ToString());
        }

        if(ImportEligCPA != null && ImportEligCPA.IsCompletedSuccessfully && ImportEligCCRS == null)
        {
            SqlCommand cmd = new SqlCommand("dbo.spImportDetail", conCCRS) { CommandType = CommandType.StoredProcedure, CommandTimeout = 0 };
            cmd.Parameters.Add("@FileName", SqlDbType.VarChar);
            cmd.Parameters["@FileName"].Value = "Detail.txt";
            ImportEligCCRS = cmd.ExecuteNonQueryAsync();
            allTasks.Add(ImportEligCCRS);
            Console.WriteLine("Started Detail Import 2 " + stopwatch.Elapsed.ToString());
        }

        if (ImportHdrCPA.IsCompletedSuccessfully && ImportEligCPA != null && ImportEligCPA.IsCompletedSuccessfully && ProcessCPA == null)
        {
            SqlCommand cmd = new SqlCommand("dbo.spProcess", conCPA) { CommandType = CommandType.StoredProcedure, CommandTimeout = 0 };
            ProcessCPA = cmd.ExecuteNonQueryAsync();
            allTasks.Add(ProcessCPA);
            Console.WriteLine("Started Processing 1 " + stopwatch.Elapsed.ToString());
        }

        if (ImportHdrCCRS != null && ImportHdrCCRS.IsCompletedSuccessfully && ImportEligCCRS != null && ImportEligCCRS.IsCompletedSuccessfully && ProcessCCRS == null)
        {
            SqlCommand cmd = new SqlCommand("dbo.spProcess", conCCRS) { CommandType = CommandType.StoredProcedure, CommandTimeout = 0 };
            ProcessCCRS = cmd.ExecuteNonQueryAsync();
            allTasks.Add(ProcessCCRS);
            Console.WriteLine("Started Processing 2 " + stopwatch.Elapsed.ToString());
        }                  

        if (ProcessCCRS != null && ProcessCPA != null)
        {
            Task.WaitAll(allTasks.ToArray());
            allTasks.Clear();
        }

        Thread.Sleep(5000);
    }

这是我在 WinForms 应用程序中使用的代码,用于为用户提供重试或取消 I/O 请求的选项。 如果在您提供的任何代码中抛出异常,那么它会弹出一个包含异常消息的对话框,并询问用户是否要重试或取消。 如果他们选择重试,它将重试。 如果他们选择取消,它将重新抛出异常。

如果您不使用 WinForms,您可以修改向用户发出请求的方式 - 或者只重试特定次数而无需用户干预。

即使您使用的是 WinForms,您也可能需要对代码进行一些修改。 我把它放在表单的代码中,因此调用Invoke

这有两种版本:一种用于同步,一种用于异步。

/// <summary>
/// Gives the option to retry if the provided action throws an exception
/// </summary>
/// <param name="action">The action to perform</param>
public void RetryableAction(Action action) {
    while (true) {
        try {
            action();
            break;
        } catch (Exception e) {
            var dr = DialogResult.Retry;
            Invoke((MethodInvoker) (() => dr = MessageBox.Show(this,
                $"There was an error:\r\n{e.Message}\r\n\r\nDo you want to retry?", "Error",
                MessageBoxButtons.RetryCancel, MessageBoxIcon.Error)));

            if (dr == DialogResult.Cancel) {
                throw;
            }
        }
    }
}

public async Task RetryableAction(Func<Task> action) {
    while (true) {
        try {
            await action();
            break;
        } catch (Exception e) {
            var dr = DialogResult.Retry;
            Invoke((MethodInvoker)(() => dr = MessageBox.Show(this,
                $"There was an error:\r\n{e.Message}\r\n\r\nDo you want to retry?", "Error",
                MessageBoxButtons.RetryCancel, MessageBoxIcon.Error)));

            if (dr == DialogResult.Cancel) {
                throw;
            }
        }
    }
}

以下是您将如何使用它的示例(在异步版本的情况下):

await RetryableAction(async () => {
    uploadHdr = await hdrBlob.UploadFromStreamAsync(fsHdr);
});

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM