1

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

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

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 вместо ... Так как делать это мои проблемы ушли, и семантический я могу сделать то же самое. Спасибо всем за помощь.

+2

Не будет работать с 'worker.RunWorkerAsync();' а не 'this.ProcessAsync (data, count);'? –

+0

@Marc Gravell: В этом случае, я думаю, ему придется использовать глобальный счетчик. – Amsakanna

+0

Единственный способ, которым я смог получить * этот код *, чтобы терпеть неудачу, как вы описали, - это рандомизировать 'count', чтобы начать между 1 и 4 (включительно) и заставить' Logger.Fail' выбросить исключение. –

ответ

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

EDIT: Предложение
Положите Try-фиксатор вокруг вызова Logger.Fatal и посмотреть, что происходит.

EDIT: Еще одно предложение
Я подозреваю, что вы не разделяют достаточно кода для нас, чтобы помочь. Ключом к успеху здесь было бы изолировать проблему в фиктивном проекте, у которого достаточно кода, чтобы показать сбой. Я был бы готов поспорить, что если вы можете это сделать, вам, скорее всего, не нужно будет публиковать это как вопрос здесь ...

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

+2

Согласен - код плаката отлично работает в VS 2010 с вызовами Console.Writeline() вместо вызовов класса Logger. Я положил свои деньги на идею Остина Logger. Fatal() выбрасывает исключение. –

+0

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

+0

Да, код определенно работает. Есть ли зависимость от третьей стороны, помимо «Logger», которую Саймон уже упомянул? – Nayan

1

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

+0

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

+2

Это не рекурсивно, ProcessAsync уже вышел к моменту запуска события. –

1

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

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

+0

Согласен. Может быть, он может использовать отдельный поток, чтобы избежать зависаний UI ?! – Nayan

+0

У него уже есть нить, ему не нужен другой. –

+0

Я не это имел в виду. Если он может, он должен отделить пользовательский интерфейс и фоновые задачи. – Nayan

0

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

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

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

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

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

+0

Есть ли другой способ настроить процесс, чтобы автоматически повторить попытку за x период времени ... –

Смежные вопросы