Frage

Wie Ereignis von einem separaten C # Programm feuern?

Das C # Programm arbeite ich an zwei getrennte Komponenten: Aufgabe Creator (TC) und Task-Prozessor (TP). TC ist mit einem Web-Service angebracht, die ständig neue Aufgaben in einer Datenbanktabelle einfügt. Auf der anderen Seite liest TP aus derselben Tabelle und verarbeitet jede Aufgaben aktualisiert dann den Status wieder auf die gleiche Tabelle. Es ist fast wie eine Schlange, aber unter Verwendung von Datenbank durchgeführt, anstatt z MSMQ. Alle 5 Sekunden TP wacht auf und liest aus der Tabelle unverarbeiteter Aufgaben zu überprüfen, was jedoch einige Auswirkungen auf die Leistung hat. Wenn es keine neue Aufgaben ist, ist es ein bisschen Abfall eine Auswahl aus der SQL-Anweisung zu feuern. Der ideale Weg ist, eine Art von Benachrichtigungsmethode haben, dass, wenn neue Aufgaben TP benachrichtigt wird eingeführt und dann erwacht aus seinem Traum für neue Aufgaben zu überprüfen.

Aktuelle Lösung:

Diagramm der aktuellen Lösung http://yuml.me/3b49bcfd

Die ideale Lösung:

Diagramm idealsolution http://yuml.me/5cf843a5

War es hilfreich?

Lösung

Ich würde MSMQ empfehlen. :) Ich bin nicht sicher, warum Sie es nicht verwenden, aber haben Sie es in Ihrer Frage erwähnen. Das ist so ziemlich genau das, was MSMQ für ... dauerhaft Vielseitigkeits zwischen Anwendungen konzipiert wurde. Es unterstützt in erster Linie das pub / sub Nachrichtenmodell ..., die auf Ihrer „ideale Lösung“ basiert ist genau das, was Sie brauchen: TC der Verleger ist, TP ein Teilnehmer ist. TC registriert die Aufgabe, fällt dann eine Nachricht in der Warteschlange veröffentlichen. Die TP-Task muss nicht sein und läuft für TC erfolgreich eine Nachricht in der Warteschlange fallen, aber wenn die TP-Task ausgeführt wird, es Benachrichtigungen und Griff Nachrichten in der Warteschlange in der priorisierten Reihenfolge erhält die ankommen.

Wenn MSMQ keine Option ist, können Sie auch WCF verwenden. Anstatt pub / sub, mit WCF könnten Sie für einen FAF entscheiden (Feuer und vergessen) Nachrichtenmodell. TP würde einen Dienst veröffentlichen, die TC verbrauchen würde. TC würde nur eine Nachricht aus, um TP Dienst feuern muß TP neuer Aufgaben zu informieren. Der Nachteil dieses Modells ist, dass TC auf TP abhängig ist, was als Idee weniger sein könnte. TP hat auch die erfolgreiche Funktion für TC ausgeführt werden, da es auf TP Dienst abhängig ist. Mit dem MSMQ Ansatz, weder TP noch TC sind voneinander abhängig, sie auf MSMQ nur abhängig sind (einer unteren Kopplungs Ansatz.)

EDIT:

Ein Beispiel, wie MSMQ zu verwenden, um Feuer Ereignisse von TC und reagieren auf Ereignisse in TP.

// TC message queue manager, sends messages
public class TaskMessageQueueManager
{
  public void NotifySubscribersOfNewTasks()
  {
    var queue = getQueue(".\private$\TaskNotifications");
    queue.Send("Tasks waiting.");
  }

  private MessageQueue getQueue(string name)
  {
    MessageQueue queue = null;
    try
    {
      if (!MessageQueue.Exists(name))
      {
        queue = MessageQueue.Create(name);
      }
      else
      {
        queue = new MessageQueue(name);
      }
    } 
    catch (Exception ex)
    {
      throw new InvalidOperationException("An error occurred while retrieving the message queue '" + name + "'.", ex);
    }

    return queue;
  }
}

// TP message queue handler, receives messages
public class TaskMessageQueueHandler
{
  private Thread m_thread;
  private ManualResetEvent m_signal;

  public void Start()
  {
    m_signal = new ManualResetEvent(false);
    m_thread = new Thread(MSMQReceiveLoop);
    m_thread.Start();

  }

  public void Stop()
  {
    m_signal.Set();
  }

  private void MSMQReceiveLoop()
  {
    bool running = true;
    MessageQueue queue = getQueue(".\private$\TaskNotifications");

    while (running)
    {
      try
      {
        var message = queue.Receive(); // Blocks here until a message is received by MSMQ

        if (message.Body.ToString() == "Tasks waiting.")
        {
          // TODO: Fire off process, perhaps another thread, to handle waiting tasks
        }

        if (m_signal.WaitOne(10)) // Non-blocking check for exit signal
        {
          running = false; // If Stop method has been called, the signal will be set and we can end loop
        } 
      }
      catch
      {
         // handle error
         running = false;
      }
    }
  }
}

Die Meldung muss nicht einfacher Text sein. Sie können ein Objekt oder Objektgraphen senden, und es wird automatisch serialisiert und als XML standardmäßig formatiert werden. Ich glaube, Sie können auch serialize Daten in einem binären Format, wenn es das ist, was Sie brauchen. So oder so, werden Sie feststellen, dass es keine Thread.Sleep Anrufe oder Polling überall. Die Schleife beendet basierend auf einem Manual, so dass Sie sauber ohne einen harten Abbruch, den Faden beenden.

Andere Tipps

  

Wenn es gibt keine neue Aufgaben, die es ein bisschen von Abfällen ist ein feuern wählen Sie aus der SQL-Anweisung.

Ein auswählen, die auf einer einzigen Tabelle, alle 5 s mit einfachen Kriterien und keine Zeilen zurückgegeben kostet in der Regel so gut wie nichts, Sorgen Sie sich nicht.

Schauen Sie sich SQL Server 2005 Abfragebenachrichtigungen . Ich habe gelernt, dass es scheint, dass es von SQL Server 2008 gezogen worden ist, damit es nicht die beste Idee, nachdem alle sein könnte.

Ich Sekunde, dass MSMQ ist wahrscheinlich eine viel bessere Möglichkeit. In Kombination mit nServiceBus einen Gewinner haben.

Ein weiterer Ansatz könnte Thread Synchronisierungsereignisse sein.

In TP man so etwas haben könnte:

EventWaitHandle taskEvent = new EventWaitHandle(true,
                EventResetMode.AutoReset,
                "newTask",
                out wasCreated);
new Thread(WaitForTask).Start();
...

public void WaitForTask() { while (true) { taskEvent.WaitOne(); ProcessTasks();} }

Und in TC:

bool eventExist;
while (!eventExist)
{
    try
    {
        taskEvent= EventWaitHandle.OpenExisting("newTask");
        eventExist = true;
    }
    catch (WaitHandleCannotBeOpenedException)
    {
        eventExist = false;
        Thread.Sleep(1000);
    }
}

CreateNewTask();
taskEvent.Set();

Nicht, dass ich sehe, wie ein Anruf alle 5 Sekunden eine solche Leistung Schwein sein könnte.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top