tutorial tareas programadas horizon colas mysql laravel laravel-5 queue innodb

mysql - tareas - ¿Cómo evitar que los bloqueos de la tabla de base de datos de trabajos se produzcan cuando se utilizan las colas de Laravel?



laravel queue tutorial (3)

Estoy escribiendo un sistema de gestión de colas en Laravel, tengo varios trabajos que tienen varios usuarios a los que debo enviar correos electrónicos. Estoy ejecutando muchos trabajadores con supervisor y para evitar el envío de múltiples correos electrónicos al mismo usuario, escribí este código. Espero que ayude a alguien con este problema.

DB::transaction(function () use ($job) { if (!count($job->jobUsers()->sharedLock()->get())) { // to share reading ability btw multiple workers Log::info(''There is no user in this job''); $job->status = Job::STATUS_FINISHED; $job->save(); return; } foreach ($job->jobUsers as $jobUser) { Log::info($jobUser->user_id); JobUser::where(''job_id'', $jobUser->job_id) ->where(''user_id'', $jobUser->user_id) ->lockForUpdate() // exclusive lock ->update([''status'' => JobUser::STATUS_SENT]); } });

Estoy usando Laravel 5.1.

Las colas se utilizan para obtener / sincronizar datos entre varios sistemas.

Uso el controlador de la base de datos, 3 procesos "artesanados de cola: trabajo - demonio" se ejecutan todo el tiempo.

Los trabajos son enviados tanto por los usuarios del sistema como por el programador (cron). Se utilizan tres colas para priorizar los trabajos.

Todo parece estar funcionando bien: la tabla de trabajos se llena de registros, el sistema se ocupa de ellos y elimina los que están listos.

Sin embargo, después de algún tiempo, los problemas de bloqueo comienzan a interferir:

SQLSTATE [40001]: Error de serialización: se encontró 1213 interbloqueo al intentar bloquearse; intente reiniciar la transacción

y

''RuntimeException'' con el mensaje ''No se puede intercambiar la instancia de PDO dentro de la transacción''.

y

SQLSTATE [HY000]: Error general: 1205 Se excedió el tiempo de espera de bloqueo; intente reiniciar la transacción

No he intentado usar otro controlador de cola todavía. Realmente me gustaría quedarme con la base de datos. El motor es InnoDB, la tabla de trabajos tiene una estructura e índices predeterminados.

¿Hay alguna manera de resolver este problema? ¿Cuáles son tus pensamientos?

Podría valer la pena mencionar que llamo a DB::reconnect() dentro de mis clases de trabajo ya que los trabajadores de la cola se ejecutan como demonios.

Los trabajos se envían utilizando el rasgo DispatchesJobs como uno esperaría. No interfiero con el algoritmo de colas de ninguna otra manera.


Podría cambiar a MyISAM y eso eliminaría los errores de transacción; pero al mismo tiempo perdería una gran funcionalidad y confiabilidad que viene con innoDB.

* Esta no es una opción si las tablas tienen claves externas y usted confía en cosas como las eliminaciones en cascada y las actualizaciones que solo se encuentran en innoDB


Puede que esta no sea la respuesta, pero alguna información.

Al usar las SELECT ... FOR UPDATE , puede observar la contención de bloqueo (bloqueos muertos, etc.).

select … for update where x <= y

su rango de exploración con <= la base de datos bloquea todas las filas <= y, incluyendo cualquier espacio vacío, por lo tanto, si tiene filas con y así: 1, 3, 5 bloquea incluso el espacio vacío entre 1 y 3 en el índice al que se llama espacio cierre

Puede ver el problema con este comando:

SHOW ENGINE INNODB STATUS; ---TRANSACTION 72C, ACTIVE 755 sec 4 lock struct(s), heap size 1248, 3 row lock(s), undo log entries 1 MySQL thread id 3, OS thread handle 0x7f84a78ba700, query id 163 localhost msandbox TABLE LOCK table test.t trx id 72C lock mode IX RECORD LOCKS space id 19 page no 4 n bits 80 index age of table test.t trx id 72C lock_mode X RECORD LOCKS space id 19 page no 3 n bits 80 index GEN_CLUST_INDEX of table test.t trx id 72C lock_mode X locks rec but not gap RECORD LOCKS space id 19 page no 4 n bits 80 index age of table test.t trx id 72C lock_mode X locks gap before rec

Última línea

Si tiene muchos bloqueos de huecos en sus transacciones que afectan la concurrencia y el rendimiento, puede deshabilitarlos de dos maneras diferentes:

1- Change the ISOLATION level to READ COMMITTED. In this isolation level, it is normal and expected that query results can change during a transaction, so there is no need to create locks to prevent that from happening. 2- innodb_locks_unsafe_for_binlog = 1. Disables the gap locks except for foreign-key constraint checking or duplicate-key checking.

https://www.percona.com/blog/2012/03/27/innodbs-gap-locks/