Cómo hacer programación dirigida por eventos entre los 2 programas separados de C #?

StackOverflow https://stackoverflow.com/questions/1339243

  •  20-09-2019
  •  | 
  •  

Pregunta

Como el fuego de evento desde un programa en C # separada?

El programa de C # que estoy trabajando tiene dos componentes separados: Tarea Creador (TC) y el procesador de tareas (TP). TC está unido a un servicio web que inserta constantemente nuevas tareas en una tabla de base de datos. Por otro lado TP lee de la misma mesa y procesa cada tarea a continuación, actualiza el estado de nuevo a la misma mesa. Es casi como una cola, pero hace usando la base de datos en lugar de, por ejemplo, MSMQ. Cada 5 segundos TP se despierta y se lee de la tabla para comprobar si las tareas no procesadas sin embargo, esto tiene algunos impactos en el rendimiento. Cuando no hay nuevas tareas que es un poco de residuos para disparar una consulta SQL desde dónde. La forma ideal es tener algún tipo de método de notificación que cuando se introducen nuevas tareas TP recibirá una notificación y luego se despierta de su sueño para comprobar si hay nuevas tareas.

Solución actual:

diagrama de solución actual http://yuml.me/3b49bcfd

La solución ideal:

diagrama de idealsolution http://yuml.me/5cf843a5

¿Fue útil?

Solución

Yo recomendaría MSMQ. :) No estoy seguro de por qué no lo está utilizando, sin embargo usted lo mencionó en su pregunta. Esto es casi exactamente lo MSMQ fue diseñado para ... concurso completo duradera entre las aplicaciones. Es principalmente apoya la / sub mensaje modelo pub ... que basó en su "solución ideal" es exactamente lo que necesita: TC es el editor, TP es un suscriptor. TC registra la tarea, a continuación, deja caer un mensaje en su cola publicar. La tarea TP no tiene que estar en funcionamiento para TC a caer correctamente un mensaje en su cola, sin embargo, cuando la tarea TP se está ejecutando, recibirá notificaciones y gestionar los mensajes en la cola en el orden de prioridad el llegar.

Si MSMQ no es una opción, se puede también utilizar WCF. En lugar de pub / sub, con WCF se puede optar por un FAF (dispara y olvida) modelo de mensaje. TP publicaría un servicio que consumiría TC. TC sólo se necesitaría para disparar un mensaje fuera de servicio de TP para notificar TP de nuevas tareas. La desventaja de este modelo es que TC depende de TP, que podría ser inferior a la idea. TP también tiene que estar en ejecución para TC para funcionar correctamente, ya que depende de servicio de TP. Con el enfoque de MSMQ, ni TP ni TC son dependientes entre sí, son dependientes sólo de MSMQ (un enfoque de acoplamiento inferior.)

EDIT:

Un ejemplo de cómo utilizar MSMQ para desencadenar eventos de TC y responder a eventos de 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;
      }
    }
  }
}

El mensaje no tiene que ser un texto simple. Puede enviar un gráfico de objetos o un objeto, y será automáticamente serializada y con formato de XML por defecto. Creo que también se puede serializar los datos en un formato binario, si eso es lo que necesita. De cualquier manera, usted notará que no hay llamadas Thread.Sleep o de votación en cualquier lugar. El bucle termina en base a un ManualResetEvent, lo que le permite terminar limpiamente el hilo sin abortar duro.

Otros consejos

  

Cuando no hay nuevas tareas que es un poco de residuos para encender un selecto desde donde instrucción SQL.

Una selección en una sola tabla, cada 5 segundos con criterios simples y ninguno filas devueltas por lo general cuesta casi nada, no se preocupe.

Salida SQL Server 2005 notificaciones de consulta . Me acabo de enterar de que parece que ha sido retirado de SQL Server 2008 por lo que podría no ser la mejor idea después de todo.

Me segundo que MSMQ es probablemente una manera mucho mejor. Combinado con nServiceBus que podría tener un ganador.

Otro enfoque podría ser eventos de sincronización de rosca.

En TP usted podría tener algo como:

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

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

Y en TC:

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

CreateNewTask();
taskEvent.Set();

No es que yo veo como una llamada cada cinco segunda causa sería un cerdo tales rendimiento.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top