Receitas do PostgreSQL: Agendador de tarefas assíncronas

Para preparar o agendador de tarefas assíncrono, precisamos do postgres e de sua extensão pg_task . (Forneci links para o meu fork do postgres, porque fiz algumas alterações que ainda não foram inseridas no repositório original. Você também pode usar a imagem pronta .)

(Existe um erro no PL / pgSQL no PostgreSQL original, devido ao qual meu agendador não funciona corretamente quando ocorre uma exceção não capturada em uma tarefa escrita em PL / pgSQL. Descrevi esse erro aqui e o corrigi no meu fork aqui .)

Para instalar o planejador, você não precisa criar uma extensão no (cada) banco de dados. Em vez disso, basta adicioná-lo ao arquivo de configuração

shared_preload_libraries = 'pg_task' 

Após reiniciar o PostgreSQL, o planejador criará tabelas de tarefas em todos os bancos de dados em nome dos usuários do banco de dados e nos esquemas padrão para esses usuários.

Se você deseja que o planejador seja executado apenas para bancos de dados específicos, é possível especificá-los no arquivo de configuração

 pg_task.database = 'database1,database2' 

Se você deseja executar o planejador não a partir de usuários do banco de dados, isso também pode ser definido como

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

Se você precisar criar tabelas do agendador que não estejam no esquema padrão para usuários, poderá configurá-lo desta maneira

 pg_task_schema.database1 = schema3 

Se você também precisar nomear a tabela do agendador de maneira diferente, poderá fazê-lo assim

 pg_task_table.database1 = table3 

Por padrão, o planejador verifica tarefas a cada 1000 ms, mas isso pode ser alterado da seguinte maneira

 pg_task_period.database1 = 100 pg_task_period.database2 = 10 

Portanto, o planejador cria (se ainda não foi criado) (um esquema, se necessário) e) uma tabela de tarefas com essas colunas

 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 fato, o planejador inicia vários fluxos de trabalho em segundo plano: um para rastrear alterações no arquivo de configuração e iniciar / parar, se necessário, os outros processos em segundo plano do planejador. E um fluxo de trabalho em segundo plano para cada banco de dados para verificar tarefas agendadas em cada banco de dados e iniciar tarefas, se necessário.

Por exemplo, se queremos concluir a tarefa o mais rápido possível, executamos o comando SQL

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

O planejador grava o resultado da tarefa na coluna de resultados em formato de texto. Se, como resultado da execução da tarefa, houver várias colunas, o agendador as adicionará ao cabeçalho junto com os tipos de coluna. Além disso, como resultado da tarefa, pode haver várias linhas, todas elas serão adicionadas à coluna de resultados.

Se queremos concluir uma tarefa, por exemplo, após 5 minutos, escrevemos o tempo planejado na coluna correspondente

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

e se quisermos que a tarefa seja concluída em um horário específico, vamos anotá-la

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

Se precisamos que a tarefa seja executada a cada 5 minutos, escrevemos assim

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

se assim for escrever

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

a tarefa será repetida 5 minutos após a conclusão da tarefa (e não após o horário agendado, por padrão).

Se uma exceção ocorrer durante a execução de uma tarefa, ela é interceptada e gravada em forma de texto na coluna de resultados, e o estado correspondente é atribuído à tarefa.

Por exemplo

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

Se for necessário que, para uma fila de tarefas, não sejam executadas mais de 2 tarefas simultaneamente, criamos tarefas pelo comando

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

Suponha que nesta fila tenhamos acumulado muitas tarefas e elas sejam executadas simultaneamente por 2. Se você criar uma tarefa com o comando

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

será executado o mais rápido possível de todas as outras tarefas nesta fila, ou seja, ainda é algo como prioridade

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


All Articles