database job-queue

database - La mejor forma de usar una tabla DB como mensaje/cola de trabajos



job-queue (4)

Tengo una tabla de bases de datos con ~ 50K filas en ella, cada fila representa un trabajo que debe hacerse. Tengo un programa que extrae un trabajo de la BD, hace el trabajo y devuelve el resultado a la base de datos. (este sistema se está ejecutando en este momento)

Ahora quiero permitir que más de una tarea de procesamiento realice trabajos, pero asegúrese de que ninguna tarea se realice dos veces (ya que una preocupación de rendimiento no es que esto cause otros problemas). Debido a que el acceso es a través de un sproce, mi corriente actual es reemplazar dicho sproce con algo que se parece a esto

update tbl set owner=connection_id() where avalable and owner is null limit 1; select stuff from tbl where owner = connection_id();

Por cierto; las tareas de los trabajadores pueden tener que ver con la conexión entre obtener un trabajo y enviar los resultados. Además, no espero que DB siquiera se acerque a ser el cuello de la botella a menos que arruine esa parte (~ 5 trabajos por minuto)

¿Hay algún problema con esto? ¿Hay una mejor manera de hacer esto?

Nota: la "Base de datos como antipatrón IPC" solo tiene un pequeño propósito aquí porque 1) No estoy haciendo IPC (no hay ningún proceso que genere las filas, todas ellas ya existen en este momento) y 2) la queja principal descrita para ese anti-patrón es que resulta en una carga innecesaria en el DB mientras los procesos esperan mensajes (en mi caso, si no hay mensajes, todo puede cerrarse ya que todo está hecho)


Al igual que un posible cambio tecnológico, puede considerar usar MSMQ o algo similar.

Cada uno de sus trabajos / subprocesos podría consultar la cola de mensajes para ver si hay un nuevo trabajo disponible. Como el acto de leer un mensaje lo elimina de la pila, se asegura de que solo un trabajo / hilo reciba el mensaje.

Por supuesto, esto es asumiendo que está trabajando con una plataforma de Microsoft.


En lugar de tener owner = null cuando no es de su propiedad, debe establecerlo en un falso registro de nadie. La búsqueda de null no limita el índice, puede terminar con un escaneo de tabla. (esto es para Oracle, el servidor SQL puede ser diferente)


Está intentando implementar el antipatrón de "Base de datos como IPC". Búsquelo para comprender por qué debería considerar rediseñar su software correctamente.


Esto es lo que he usado exitosamente en el pasado:

Esquema de tabla MsgQueue

MsgId identity -- NOT NULL MsgTypeCode varchar(20) -- NOT NULL SourceCode varchar(20) -- process inserting the message -- NULLable State char(1) -- ''N''ew if queued, ''A''(ctive) if processing, ''C''ompleted, default ''N'' -- NOT NULL CreateTime datetime -- default GETDATE() -- NOT NULL Msg varchar(255) -- NULLable

Sus tipos de mensajes son lo que usted esperaría: mensajes que se ajustan a un contrato entre la (s) inserción (es) del proceso y la (s) lectura (es) del proceso, estructurados con XML u otra representación de la representación (JSON sería útil en algunos casos para ejemplo).

Entonces, los procesos de 0 a n se pueden insertar, y los procesos de 0 a n pueden leer y procesar los mensajes. Cada proceso de lectura generalmente maneja un tipo de mensaje único. Se pueden ejecutar varias instancias de un tipo de proceso para equilibrar la carga.

El lector saca un mensaje y cambia el estado a "A" mientras trabaja en él. Cuando termina, cambia el estado a "C" ompleto. Puede eliminar el mensaje o no dependiendo de si desea mantener el seguimiento de auditoría. Los mensajes de estado = ''N'' se extraen en orden MsgType / Timestamp, por lo que hay un índice en MsgType + State + CreateTime.

Variaciones:
Estado para "E" rror.
Columna para el código de proceso de Reader.
Indicaciones de tiempo para transiciones de estado.

Esto ha proporcionado un mecanismo agradable, escalable, visible y simple para hacer una serie de cosas como las que está describiendo. Si tiene una comprensión básica de las bases de datos, es bastante infalible y extensible.

Código de comentarios:

CREATE PROCEDURE GetMessage @MsgType VARCHAR(8) ) AS DECLARE @MsgId INT BEGIN TRAN SELECT TOP 1 @MsgId = MsgId FROM MsgQueue WHERE MessageType = @pMessageType AND State = ''N'' ORDER BY CreateTime IF @MsgId IS NOT NULL BEGIN UPDATE MsgQueue SET State = ''A'' WHERE MsgId = @MsgId SELECT MsgId, Msg FROM MsgQueue WHERE MsgId = @MsgId END ELSE BEGIN SELECT MsgId = NULL, Msg = NULL END COMMIT TRAN