Recetas PostgreSQL: Programador de tareas asíncrono

Para preparar el programador de tareas asíncrono, necesitamos los propios postgres y su extensión pg_task . (Le di enlaces a mis postgres de fork, porque hice algunos cambios que aún no se han podido incluir en el repositorio original. También puede usar la imagen preparada ).

(Hay un error en PL / pgSQL en el PostgreSQL original, debido a que mi programador no funciona correctamente cuando ocurre una excepción no detectada en una tarea escrita en PL / pgSQL. Describí este error aquí y lo arreglé en mi tenedor aquí ).

Para instalar el programador, no necesita crear una extensión en (cada) base de datos. En cambio, solo agréguelo al archivo de configuración

shared_preload_libraries = 'pg_task' 

Después de reiniciar PostgreSQL, el planificador creará tablas de tareas en todas las bases de datos en nombre de los usuarios de la base de datos y en los esquemas predeterminados para estos usuarios.

Si desea que el planificador se ejecute solo para bases de datos específicas, puede especificarlas en el archivo de configuración

 pg_task.database = 'database1,database2' 

Si desea ejecutar el planificador no desde los usuarios de la base de datos, esto también se puede configurar como

 pg_task.database = 'database1:user1,database2:user2' 

Si necesita crear tablas de planificador que no estén en el esquema predeterminado para los usuarios, puede configurarlo así

 pg_task_schema.database1 = schema3 

Si también necesita nombrar la tabla del planificador de manera diferente, puede hacerlo así

 pg_task_table.database1 = table3 

Por defecto, el planificador verifica las tareas cada 1000 ms, pero esto se puede cambiar de la siguiente manera

 pg_task_period.database1 = 100 pg_task_period.database2 = 10 

Entonces, el planificador crea (si no se ha creado) (un esquema, si es necesario, y) una tabla de tareas con tales columnas

 id BIGSERIAL NOT NULL PRIMARY KEY, -- ,   dt TIMESTAMP NOT NULL DEFAULT NOW(), --     (- -   ) start TIMESTAMP, --     stop TIMESTAMP, --      queue TEXT NOT NULL DEFAULT 'default', --    (      ) max INT, --        (,      ) pid INT, --  ,    request TEXT NOT NULL, --  SQL   response TEXT, --    state TEXT NOT NULL DEFAULT 'QUEUE', --   (- - ,    , , ...) timeout INTERVAL, --      delete BOOLEAN NOT NULL DEFAULT false, --     ,    repeat INTERVAL, --    drift BOOLEAN NOT NULL DEFAULT true --        

De hecho, el planificador inicia varios flujos de trabajo en segundo plano: uno para rastrear los cambios en el archivo de configuración e iniciar / detener, si es necesario, los otros procesos en segundo plano del planificador. Y un flujo de trabajo en segundo plano para cada base de datos para verificar las tareas programadas en cada base de datos e iniciar tareas si es necesario.

Por ejemplo, si queremos completar la tarea lo más rápido posible, entonces ejecutamos el comando SQL

 INSERT INTO task (request) VALUES ('SELECT now()') 

El planificador escribe el resultado de la tarea en la columna de resultados en forma de texto. Si como resultado de la ejecución de la tarea hay varias columnas, el planificador las agregará al encabezado junto con los tipos de columna. Además, como resultado de la tarea, puede haber varias líneas, todas ellas se agregarán a la columna de resultados.

Si queremos completar una tarea, por ejemplo, después de 5 minutos, entonces escribimos el tiempo planificado en la columna correspondiente

 INSERT INTO task (dt, request) VALUES (now() + '5 min':INTERVAL, 'SELECT now()') 

y si queremos que la tarea se complete en un momento específico, la anotaremos

 INSERT INTO task (dt, request) VALUES ('2019-07-01 00:00:00', 'SELECT now()') 

Si necesitamos que la tarea se realice cada 5 minutos, entonces escribimos así

 INSERT INTO task (repeat, request) VALUES ('5 min', 'SELECT now()') 

si es así escribe

 INSERT INTO task (repeat, request, drift) VALUES ('5 min', 'SELECT now()', false) 

entonces la tarea se repetirá 5 minutos después de la finalización de la tarea (y no después de la hora programada, como por defecto).

Si se produce una excepción durante la ejecución de una tarea, se intercepta y se escribe en forma de texto en la columna de resultados, y se asigna el estado correspondiente a la tarea.

Por ejemplo

 INSERT INTO task (request) VALUES ('SELECT 1/0') 

Si es necesario que para una cola de tareas no se ejecuten más de 2 tareas simultáneamente, entonces creamos tareas mediante el comando

 INSERT INTO task (queue, max, request) VALUES ('queue', 2, 'SELECT now()') 

Supongamos que en esta cola hemos acumulado muchas tareas y que son ejecutadas simultáneamente por 2. Si crea una tarea por

 INSERT INTO task (queue, max, request) VALUES ('queue', 3, 'SELECT now()') 

entonces se ejecutará tan pronto como sea posible de todas las demás tareas en esta cola, es decir sigue siendo algo como prioridad

Source: https://habr.com/ru/post/456722/


All Articles