2015-03-13 13 views
8

Ich wechsle von Task.Run zu Hangfire. In .NET 4.5 + Task.Run kann Task<TResult> zurückgeben, mit dem ich Tasks ausführen kann, die anders als void zurückgeben. Ich kann in der Regel warten und das Ergebnis meiner Aufgabe erhalten, indem der Eigenschaft Zugriff auf MyReturnedTask.ResultHangfire-Hintergrundjob mit Rückgabewert

Beispiel meines alten Code:

public void MyMainCode() 
{ 
    List<string> listStr = new List<string>(); 
    listStr.Add("Bob"); 
    listStr.Add("Kate"); 
    listStr.Add("Yaz"); 

    List<Task<string>> listTasks = new List<Task<string>>(); 

    foreach(string str in listStr) 
    { 
     Task<string> returnedTask = Task.Run(() => GetMyString(str)); 
     listTasks.Add(returnedTask); 
    } 

    foreach(Task<string> task in listTasks) 
    { 
     // using task.Result will cause the code to wait for the task if not yet finished. 
     // Alternatively, you can use Task.WaitAll(listTasks.ToArray()) to wait for all tasks in the list to finish. 
     MyTextBox.Text += task.Result + Environment.NewLine; 
    } 
} 
private string GetMyString(string str) 
{ 
    // long execution in order to calculate the returned string 
    return str + "_finished"; 
} 

Soweit ich aus der Quick Start Seite von Hangfire sehen kann, Ihren Hauptmann der ist BackgroundJob.Enqueue(() => Console.WriteLine("Fire-and-forget")); perfekt läuft der Code als Hintergrund-Job, aber anscheinend nicht unterstützt Jobs, die einen Rückgabewert (wie der Code, den ich oben dargestellt). Ist das richtig? wenn nicht, wie kann ich meinen Code optimieren, um Hangfire zu verwenden?

P.S. Ich sah schon bei HostingEnvironment.QueueBackgroundWorkItem (here), aber es fehlt offenbar die gleiche Funktionalität

EDIT

(Hintergrundjobs void sein müssen) Wie @Dejan herausgefunden, der Hauptgrund, warum ich zu Hangfire wechseln wollen, ist Der gleiche Grund, den die .NET-Leute QueueBackgroundWorkItem in .NET 4.5.2 hinzugefügt haben. Und dieser Grund ist in Scott Hanselmans großartigem article über Hintergrundaufgaben in ASP.NET gut beschrieben. Also, ich werde Zitat aus dem Artikel:

QBWI (QueueBackgroundWorkItem) plant eine Aufgabe, die im Hintergrund, unabhängig von jede Anforderung ausgeführt werden kann. Dies unterscheidet sich von einer normalen ThreadPool-Arbeitsaufgabe darin, dass ASP.NET automatisch protokolliert, wie viele Arbeitselemente über diese API aktuell ausgeführt werden, und die ASP.NET-Laufzeit versucht, das Herunterfahren von AppDomain zu verzögern, bis diese Arbeitselemente beendet sind ausgeführt werden.

+2

Der Rückgabewert der Methoden wird auf der Info-Seite des Jobs in der Systemsteuerung angezeigt. Wenn Sie in der relevanten db-Tabelle nach den Hangfire-Jobs suchen, sollte der Rückgabewert in einem Feld in dort gespeichert werden. Siehe https://github.com/HangfireIO/Hangfire/pull/161 - abgesehen davon bin ich mir nicht sicher, ob es möglich ist, darauf programmatisch zuzugreifen. – adaam

+0

Danke, dass du das herausgibst. – yazanpro

+0

Ich habe genau die gleiche Frage. Haben Sie in der Zwischenzeit etwas herausgefunden? – Dejan

Antwort

7

Eine einfache Lösung wäre, die Überwachung API abfragen, bis der Job wie dies abgeschlossen ist:

public static Task Enqueue(Expression<Action> methodCall) 
    { 
     string jobId = BackgroundJob.Enqueue(methodCall); 
     Task checkJobState = Task.Factory.StartNew(() => 
     { 
      while (true) 
      { 
       IMonitoringApi monitoringApi = JobStorage.Current.GetMonitoringApi(); 
       JobDetailsDto jobDetails = monitoringApi.JobDetails(jobId); 
       string currentState = jobDetails.History[0].StateName; 
       if (currentState != "Enqueued" && currentState != "Processing") 
       { 
        break; 
       } 
       Thread.Sleep(100); // adjust to a coarse enough value for your scenario 
      } 
     }); 
     return checkJobState; 
    } 

Achtung: Natürlich, in einem Web-hosted Szenario können Sie nicht auf Fortsetzung verlassen von die Aufgabe (task.ContinueWith()), um weitere Dinge zu erledigen, nachdem der Job beendet wurde, da die AppDomain möglicherweise heruntergefahren wird - aus den gleichen Gründen möchten Sie wahrscheinlich Hangfire an erster Stelle verwenden.

+0

Vielen Dank, und der letzte Satz über den Grund, warum ich auf Hangfire umgestiegen bin, ist vollkommen richtig. – yazanpro

+0

Der Punkt ist, dass es keine kugelsichere Lösung geben kann, bei der eine Aufgabe zurückgegeben wird. – Dejan

+0

Ich habe den gleichen Code benutzt, aber es ist immer noch ein paar Mal ausgefallen und die meiste Zeit passiert. Ich habe versucht, mit "Warte" Check und jetzt funktioniert es auch ohne Thread.Sleep. if (currentState! = "Enqueued" && currentState! = "Verarbeitung" && currentState! = "Warten") –