1

我正在处理一些调用服务的代码。此服务调用可能会失败,如果确实如此,我希望系统重试,直到它正常工作或经过太多时间。

我想知道我哪里出错了,因为以下代码似乎无法正常工作......它随机只执行一到四个循环......

protected virtual void ProcessAsync(object data, int count)
{
    var worker = new BackgroundWorker();
    worker.DoWork += (sender, e) =>
    {
        throw new InvalidOperationException("oh shiznit!");
    };
    worker.RunWorkerCompleted += (sender, e) =>
    {
        //If an error occurs we need to tell the data about it
        if (e.Error != null)
        {
            count++;
            System.Threading.Thread.Sleep(count * 5000);
            if (count <= 10)
            {
                if (count % 5 == 0)
                    this.Logger.Fatal("LOAD ERROR - The system can't load any data", e.Error);
                else
                    this.Logger.Error("LOAD ERROR - The system can't load any data", e.Error);
                this.ProcessAsync(data, count);
            }
        }
    };
    worker.RunWorkerAsync();
}

干杯安东尼

更新:

我已经将我的代码切换为使用 ThreadPool.QueueUserWorkItem ......因为这样做我的问题已经消失并且在语义上我可以做同样的事情。感谢您的所有帮助。

4

4 回答 4

4

我已经稍微修改了您的代码,并且通过 10 次迭代(VS 2008 Express)没有任何问题,这使我想到:这是实际代码吗?如果不是,您确定您已经发送了足够的内容来重现该问题?

如果我冒昧地猜测一下,我会说您发送的计数会有所不同,count % 5 > 0因此会抛出异常Logger.Fatal

private void button1_Click(object sender, EventArgs e)
{
    ProcessAsync("beer", 1);
}

protected virtual void ProcessAsync(object data, int count)
{
    var worker = new BackgroundWorker();
    worker.DoWork += (sender, e) =>
    {
        throw new InvalidOperationException("oh shiznit!");
    };
    worker.RunWorkerCompleted += (sender, e) =>
    {
        //If an error occurs we need to tell the data about it
        if (e.Error != null)
        {
            count++;
            //System.Threading.Thread.Sleep(count * 5000);
            if (count <= 10)
            {
                if (count % 5 == 0)
                    this.Logger.Fatal("LOAD ERROR - The system can't load any data - " + count.ToString(), e.Error);
                else
                    this.Logger.Error("LOAD ERROR - The system can't load any data - " + count.ToString(), e.Error);
                this.ProcessAsync(data, count);
            }
        }
    };
    worker.RunWorkerAsync();
}

SomeLogger Logger = new SomeLogger();

class SomeLogger
{
    public void Fatal(string s, Exception e)
    {
        System.Diagnostics.Debug.WriteLine(s);
    }

    public void Error(string s, Exception e)
    {
        System.Diagnostics.Debug.WriteLine(s);
    }
}

编辑:一个建议
在调用周围放置一个try-catch Logger.Fatal,看看会发生什么。

编辑:另一个建议
我怀疑您没有共享足够的代码让我们提供帮助。这里成功的关键是将问题隔离在一个只有足够代码来显示失败的虚拟项目中。我愿意打赌,如果你能做到这一点,你很可能不需要在这里发布这个问题......

你可以从我的假设开始,应该会看到这很好用。然后开始将通用代码更改为您实际使用的代码(我将从 Logger.Fatal 的实际实现开始)。该错误可能会在短时间内变得非常明显。

于 2010-05-11T04:50:06.110 回答
1

这一定是我见过的最离奇的重试机制了。你能做一个更干净的吗?避免递归调用,除非它们简单且易于维护,因为它很容易导致错误。

于 2010-05-11T04:31:19.247 回答
1

我没有看到明显的原因。但是,您的 RunWorkerCompleted 事件通常会在 UI 线程上运行。并将其挂起长达 55 秒。这是不可取的。

没有任何理由我能想到你为什么不只是在 DoWork 方法中循环使用 try/catch 块。

于 2010-05-11T04:53:44.573 回答
0

有一件事真的很糟糕

在你的RunWorkerCompleted()你调用一个Thread.Sleep(). 由于这个事实,这个函数将在您的应用程序将冻结的 GUI 线程中处理!

请不要Thread.Sleep()在 BackgroundWorker 的任何事件中调用,因为它们都将在 GUI 线程中处理。

因此,这可能不是您当前问题的真正解决方案,但绝对是您应该关心的事情。

Update
To start something after a given time period you should take a look into the various timer classes. Each of them has it's own pros and cons. For a more insight view you should take a look into this article.

于 2010-05-11T06:33:43.450 回答