BackgroundWorker действует странно - PullRequest
1 голос
/ 11 мая 2010

Я работаю над кодом, который вызывает сервис. Этот сервисный вызов может завершиться с ошибкой, и если это произойдет, я хочу, чтобы система повторила попытку, пока он не заработает или не пройдет слишком много времени.

Мне интересно, где я ошибаюсь, поскольку следующий код, кажется, не работает правильно ... Он случайным образом выполняет только один-четыре цикла ...

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();
}

Приветствие Энтони

UPDATE:

Я переключил свой код, чтобы вместо него использовать ThreadPool.QueueUserWorkItem ... После этого мои проблемы исчезли, и семантически я могу сделать то же самое. Спасибо за вашу помощь, ребята.

Ответы [ 4 ]

4 голосов
/ 11 мая 2010

Я немного изменил ваш код, и у меня нет проблем с прохождением 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);
    }
}

РЕДАКТИРОВАТЬ : предложение
Сделайте попытку вызова вокруг Logger.Fatal и посмотрите, что произойдет.

РЕДАКТИРОВАТЬ : еще одно предложение
Я подозреваю, что вы не поделились достаточным количеством кода, чтобы мы могли помочь. Ключом к успеху здесь является изоляция проблемы в фиктивном проекте, в котором достаточно кода, чтобы показать ошибку. Я был бы готов поспорить, что если вы сможете это сделать, вам, скорее всего, не нужно будет публиковать это здесь как вопрос ...

Вы можете начать с моих предположений и увидеть, что это работает просто отлично. Затем начните заменять обобщенный код на то, что вы на самом деле используете (я бы начал с реальной реализации Logger.Fatal). Ошибка, скорее всего, станет довольно очевидной в короткие сроки.

1 голос
/ 11 мая 2010

Я не вижу очевидной причины. Однако ваше событие RunWorkerCompleted обычно выполняется в потоке пользовательского интерфейса. И повесить его на целых 55 секунд. Это не может быть желательным.

Нет никаких причин, по которым я мог бы подумать, почему бы вам не просто зациклить метод DoWork с блоком try / catch.

1 голос
/ 11 мая 2010

Это должно быть самый странный механизм повторения, который я когда-либо видел. Вы можете сделать чище? Избегайте рекурсивных вызовов, если они не являются простыми и легкими в обслуживании, потому что это может легко привести к ошибкам.

0 голосов
/ 11 мая 2010

Есть одна вещь, которая действительно плохая !

В вашем RunWorkerCompleted() вы звоните Thread.Sleep(). В связи с тем, что эта функция будет обрабатываться в потоке GUI, ваше приложение будет зависать!

Пожалуйста, не вызывайте Thread.Sleep() в любом событии BackgroundWorker, потому что все они будут обработаны в потоке GUI.

Так что, возможно, это не реальное решение вашей текущей проблемы, но определенно то, о чем вам следует позаботиться.

Обновление
Чтобы начать что-то после определенного периода времени, вы должны взглянуть на различные таймеры классы . У каждого из них есть свои плюсы и минусы. Для более глубокого понимания вы должны взглянуть на эту статью .

...