Evento enq: JQ - contention ¿Por qué se detienen mis Jobs?
Recientemente, me encontré con un escenario donde los procesos de Job Queue de una base de datos Oracle parecían no avanzar. Al revisar las vistas de rendimiento, identifiqué una espera prolongada en el evento enq: JQ - contention
Para entender el problema, primero debemos recordar cómo gestiona Oracle los jobs. A partir de Oracle 11g y 12c, la arquitectura de Oracle Scheduler separa la programación de la ejecución real mediante varios procesos de fondo:
CJQ0 (Job Queue Coordinator): Es el director de orquesta. Lee la tabla de jobs, determina cuál debe ejecutarse y levanta procesos esclavos para realizar el trabajo.
Jnnn / Wnnn (Job/Worker Slaves): Son los procesos que ejecutan el código PL/SQL del job.
El Enqueue JQ es un bloqueo de nivel de instancia utilizado para serializar el control de los trabajos. Oracle lo usa para asegurar que un job no sea ejecutado por dos procesos a la vez y para gestionar la creación/terminación de los procesos esclavos.
Cuando vemos el evento enq: JQ - contention, significa que hay una fila de procesos esperando por ese "permiso". Esto suele ocurrir por saturación del coordinador, límites bajos en JOB_QUEUE_PROCESSES o jobs "zombies" que mantienen el bloqueo sin liberar el recurso.
Al ejecutar una consulta a v$session para monitorear los procesos tipo Job (J001), observamos lo siguiente:
SELECT sid, serial#, event, p1, p2, p3, seconds_in_wait FROM v$session WHERE program LIKE '%(J001)%';
Observen la columna SECONDS_IN_WAIT. El proceso lleva más de 12 horas esperando. El valor de P1 (1246822406) traducido a ASCII corresponde precisamente a 'JQ'.
Podemos obtener el valor de P1 traducido a ASCII, con el siguiente query:
SELECT chr(bitand(1246822406,-16777216)/16777216)|| chr(bitand(1246822406,16711680)/65536) AS Enqueue_Type FROM dual;
Para identificar el SPID a nivel de sistema operativo:
SELECT s.sid, p.spid, s.program, s.event FROM v$session s JOIN v$process p ON s.paddr = p.addr WHERE s.program LIKE '%(J001)%';
En este escenario, al revisar otros procesos esclavos (Workers
W...), detectamos sesiones con un LAST_CALL_ET muy alto, lo que indica que están ejecutando tareas que se quedaron colgadas o son ineficientes:SELECT p.spid, s.username, s.program, s.last_call_et FROM v$session s JOIN v$process p ON s.paddr = p.addr WHERE s.sid = 4170;
Si la contención es crítica y los jobs están paralizados, la solución más efectiva es "resetear" el coordinador de jobs:
Verificamos el valor actual del parámetro job_queue_processes.
sqlplus / as sysdbaSHOW PARAMETER "job_queue_processes";Establecemos el parámetro a cero.
ALTER SYSTEM SET job_queue_processes=0;
Si existen procesos a nivel de OS que no mueren, identificarlos por su SPID y terminarlos.
Volvemos al valor original, en este caso teníamos lo establecido en 2000.
ALTER SYSTEM SET job_queue_processes=2000;
Esto obliga al CJQ0 a reiniciarse y liberar los enqueues persistentes.
Como hemos visto, el evento enq: JQ - contention es una señal clara de que el motor de jobs está saturado o bloqueado por un proceso ineficiente. En entornos críticos, especialmente en RAC, no basta con aumentar el número de procesos; es fundamental monitorear el LAST_CALL_ET de los workers para identificar tareas "zombies" que secuestran al coordinador. Realizar un reseteo controlado de la cola de trabajos suele ser la solución más efectiva para normalizar el servicio sin afectar al resto de las instancias del cluster.