F.31. pg_cron — планировщик заданий на основе cron, работающий внутри базы данных#
F.31. pg_cron — планировщик заданий на основе cron, работающий внутри базы данных #
1.6.7:
F.31.1. Обзор? #
pg_cron — это простой планировщик заданий на основе cron для Tantor BE, который работает внутри базы данных как расширение.
F.31.2. Как работает pg_cron #
Расширение создает фоновый рабочий процесс, который отслеживает задания в таблице cron.job.
CREATE TABLE cron.job (
jobid bigint primary key default pg_catalog.nextval('cron.jobid_seq'),
schedule text not null,
command text not null,
nodename text not null default 'localhost',
nodeport int not null default pg_catalog.inet_server_port(),
database text not null default pg_catalog.current_database(),
username text not null default current_user
);
Основываясь на вашей конфигурации, для выполнения задания расширение устанавливает соединение с Postgres или запускает рабочий процесс базы данных.
pg_cron может выполнять несколько заданий параллельно, но только один экземпляр каждого конкретного задания одновременно. Если второй экземпляр запускается до завершения первого, он ставится в очередь и начинается сразу после завершения первого.
F.31.3. Синтаксис Cron #
Код в pg_cron, который обрабатывает разбор и планирование, взят непосредственно из исходного кода cron, написанного Полом Викси, поэтому поддерживаются те же параметры.
┌───────────── min (0 - 59) │ ┌────────────── hour (0 - 23) │ │ ┌─────────────── day of month (1 - 31) or last day of the month ($) │ │ │ ┌──────────────── month (1 - 12) │ │ │ │ ┌───────────────── day of week (0 - 6) (0 to 6 are Sunday to │ │ │ │ │ Saturday, or use names; 7 is also Sunday) │ │ │ │ │ │ │ │ │ │ * * * * *
Легкий способ создать расписание cron: crontab.guru.
pg_cron также позволяет вам: - использовать $ для обозначения
последнего дня месяца; - использовать [1-59] секунд
для планирования задания на основе интервала. Обратите внимание, что
секунды нельзя использовать с другими единицами времени.
Примеры расписаний cron:
'10 seconds' # every 10 seconds * * * * * # every minute */5 * * * * # every 5 minutes 0 * * * * # every hour 0 0 * * * # daily at 12AM 0 0 * * 1-5 # 12AM every weekday 0 1 * * 0 # 1AM every Sunday 0 13 2 6 * # 1PM on the 2nd of June
F.31.4. Управление и создание заданий #
Задания Cron можно управлять напрямую, взаимодействуя с таблицей cron.job, если у вас есть необходимые разрешения. Однако рекомендуется использовать функции cron:
Примечание
Политика RLS гарантирует, что задания могут просматривать и изменять только те пользователи, которые их создали, если только пользователь не является суперпользователем или не обладает атрибутом bypassrls.
F.31.4.1. Создание задания cron #
F.31.4.1.1. cron.schedule сигнатуры #
-- create job, return jobid CREATE OR REPLACE FUNCTION cron.schedule(schedule text, command text) RETURNS bigint; -- create named job, return jobid CREATE OR REPLACE FUNCTION cron.schedule(job_name text, schedule text, command text) RETURNS bigint
F.31.4.1.2. Примеры #
F.31.4.1.2.1. Создайте задание cron #
-- Delete old data on Saturday at 3:30am (GMT)
SELECT cron.schedule(
'30 3 * * 6',
$$DELETE FROM events WHERE event_time < now() - interval '1 week'$$
);
-- returns cron id
F.31.4.1.2.2. Создать именованное задание cron #
-- Vacuum every day at 10:00am (GMT)
SELECT cron.schedule(
'nightly-vacuum',
'0 10 * * *',
'VACUUM'
);
-- returns cron id
F.31.4.1.2.3. Создайте задание, которое выполняется каждые 30 секунд #
-- run SELECT 1 every 30 seconds
SELECT cron.schedule(
'run_every_30_seconds',
'30 seconds',
'SELECT 1'
);
-- returns cron id
F.31.4.1.2.4. Создайте задание, которое вызывает хранимую процедуру каждые 5 секунд #
-- Call a stored procedure every 5 seconds
SELECT cron.schedule(
'process-updates',
'5 seconds',
'CALL process_updates()'
);
-- returns cron id
F.31.4.1.2.5. Создайте задание, которое обрабатывает заработную плату в 12:00 последнего дня каждого месяца #
-- Process payroll at 12:00 of the last day of each month
SELECT cron.schedule(
'process-payroll',
'0 12 $ * *',
'CALL process_payroll()'
);
-- returns cron id
F.31.4.2. Создание задания cron в другой базе данных #
F.31.4.2.1. cron.schedule_in_database
сигнатура #
-- create job, return jobid
CREATE OR REPLACE FUNCTION cron.schedule_in_database(
job_name text,
schedule text,
command text,
database text,
username text DEFAULT NULL::text,
active boolean DEFAULT true
)
RETURNS bigint
F.31.4.2.2. Пример #
F.31.4.2.2.1. Создать задание cron в другой базе данных #
-- Delete old data on Saturday at 3:30am (GMT)
SELECT cron.schedule_in_database(
'delete_old_data',
'30 3 * * 6',
$$DELETE FROM events WHERE event_time < now() - interval '1 week'$$,
'some_other_database'
);
-- returns cron id
F.31.4.3. Удаление задания cron #
F.31.4.3.1. cron.unschedule сигнатуры #
-- remove job by name, return true if job was removed CREATE OR REPLACE FUNCTION cron.unschedule(job_name text) RETURNS boolean -- remove job by id, return true if job was removed CREATE OR REPLACE FUNCTION cron.unschedule(job_id bigint) RETURNS boolean
F.31.4.3.2. Примеры #
F.31.4.3.2.1. Удалить именованное задание cron #
-- delete job by name
SELECT cron.unschedule('nightly-vacuum');
-- returns true if job was removed
F.31.4.3.2.2. Удалить задание cron по идентификатору #
-- delete job by id SELECT cron.unschedule(42); -- returns true if job was removed
F.31.4.4. Изменение задания cron #
F.31.4.4.1. cron.alter_job сигнатура #
CREATE OR REPLACE FUNCTION cron.alter_job(
job_id bigint,
schedule text DEFAULT NULL::text,
command text DEFAULT NULL::text,
database text DEFAULT NULL::text,
username text DEFAULT NULL::text,
active boolean DEFAULT NULL::boolean
)
RETURNS void
F.31.4.4.2. Примеры #
F.31.4.4.2.1. Изменить расписание задания #
-- change job's schedule SELECT cron.alter_job(42, '0 10 * * *'); -- returns void
F.31.4.4.2.2. Изменить расписание задания, команду и имя пользователя #
-- change job's command
SELECT cron.alter_job(
42,
'0 10 * * *',
'VACUUM',
username := 'some_other_user'
);
-- returns void
F.31.4.4.2.3. Деактивировать задание #
-- deactivate job SELECT cron.alter_job(42, active := false); -- returns void
F.31.5. Настройка pg_cron #
Чтобы запустить фоновый рабочий процесс pg_cron, необходимо добавить pg_cron в
shared_preload_libraries в postgresql.conf.
Обратите внимание, что pg_cron не выполняет никакие задания, пока сервер находится в режиме
горячего
резерва, но он автоматически запускается при повышении роли сервера.
## add to postgresql.conf ## required to load pg_cron background worker on start-up shared_preload_libraries = 'pg_cron'
По умолчанию фоновый рабочий процесс pg_cron ожидает, что его метаданные будут созданы в базе данных Tantor BE. Однако вы можете изменить это, установив параметр конфигурации cron.database_name в файле postgresql.conf.
## add to postgresql.conf ## optionally, specify the database in which the pg_cron background worker should run (defaults to postgres) cron.database_name = 'postgres'
pg_cron может быть установлен только в одну базу данных в кластере.
Если необходимо запускать задания в нескольких базах данных, используйте cron.schedule_in_database().
Ранее pg_cron мог использовать только время по Гринвичу, но теперь вы можете адаптировать
ваше время, установив cron.timezone в
postgresql.conf.
## add to postgresql.conf ## optionally, specify the timezone in which the pg_cron background worker should run (defaults to GMT). E.g: cron.timezone = 'PRC'
После перезапуска Tantor BE вы можете создать функции и метаданные таблиц pg_cron с помощью CREATE EXTENSION pg_cron.
-- run as superuser: CREATE EXTENSION pg_cron; -- optionally, grant usage to regular users: GRANT USAGE ON SCHEMA cron TO marco;
F.31.5.1. Обеспечение возможности запуска заданий pg_cron #
Предупреждение
По умолчанию,
pg_cron использует libpq для открытия нового подключения к локальной
базе данных, что должно быть разрешено в
pg_hba.conf.
Возможно, потребуется включить аутентификацию trust
для подключений с localhost для пользователя, под которым выполняется cron-задание,
или вы можете добавить пароль в
файл .pgpass,
который libpq будет использовать при открытии подключения.
Вы также можете использовать каталог сокетов домена Unix в качестве имени хоста
и включить аутентификацию trust для локальных
подключений в
pg_hba.conf,
что обычно безопасно:
## Connect via a unix domain socket: cron.host = '/tmp' ## Can also be an empty string to look for the default directory: cron.host = ''
В качестве альтернативы, pg_cron может быть настроен для использования фоновых
рабочих процессов. В этом случае количество одновременных заданий ограничено
параметром max_worker_processes, поэтому вам может
потребоваться его увеличить.
## Schedule jobs via background workers instead of localhost connections cron.use_background_workers = on ## Increase the number of available background workers from the default of 8 max_worker_processes = 20
Для обеспечения безопасности задания выполняются в базе данных, в которой вызывается функция cron.schedule с теми же разрешениями, что и у текущего пользователя. Кроме того, пользователи могут видеть только свои собственные задания в таблице cron.job.
-- View active jobs select * from cron.job;
F.31.5.2. Параметры расширения #
Расширение pg_cron поддерживает следующие параметры конфигурации:
| Параметр | Значение по умолчанию | Описание |
|---|---|---|
cron.database_name
|
postgres
| База данных, в которой должен выполняться фоновый рабочий процесс pg_cron. |
cron.enable_superuser_jobs
|
on
| Разрешить планирование заданий от имени суперпользователей. |
cron.host
|
localhost
| Имя хоста для подключения к postgres. |
cron.launch_active_jobs
|
on
| Когда выключено, отключает все активные задания без необходимости перезапуска сервера |
cron.log_min_messages
|
WARNING
| log_min_messages для фонового рабочего процесса запуска (launcher bgworker). |
cron.log_run
|
on
|
Записывать все детали выполнения в таблицу
cron.job_run_details.
|
cron.log_statement
|
on
| Протоколировать все операторы cron перед выполнением. |
cron.max_running_jobs
|
32
| Максимальное количество заданий, которые могут выполняться одновременно. |
cron.timezone
|
GMT
| Часовой пояс, в котором должен работать фоновый процесс pg_cron. |
cron.use_background_workers
|
off
| Использовать фоновые рабочие процессы вместо клиентских подключений. |
F.31.5.2.1. Изменение настроек #
Чтобы просмотреть настройки конфигурации, выполните:
SELECT * FROM pg_settings WHERE name LIKE 'cron.%';
Параметр можно изменить в файле postgresql.conf или с помощью приведённой ниже команды:
ALTER SYSTEM SET cron.<parameter> TO '<value>';
cron.log_min_messages и
cron.launch_active_jobs имеют
контекст установки
параметра sighup. Они могут быть
применены путем выполнения
SELECT pg_reload_conf();.
Все остальные параметры имеют контекст postmaster и вступают в силу только после перезапуска сервера.
F.31.6. Мониторинг заданий #
F.31.6.1. Рассмотрение таблицы cron.job_run_details #
Вы можете просмотреть активность заданий в таблице cron.job_run_details:
select * from cron.job_run_details order by start_time desc limit 5; ┌───────┬───────┬─────────┬──────────┬──────────┬───────────────────┬───────────┬──────────────────┬───────────────────────────────┬───────────────────────────────┐ │ jobid │ runid │ job_pid │ database │ username │ command │ status │ return_message │ start_time │ end_time │ ├───────┼───────┼─────────┼──────────┼──────────┼───────────────────┼───────────┼──────────────────┼───────────────────────────────┼───────────────────────────────┤ │ 11 │ 4328 │ 2610 │ postgres │ marco │ select pg_sleep(3)│ running │ NULL │ 2023-02-07 09:30:00.098164+01 │ NULL │ │ 10 │ 4327 │ 2609 │ postgres │ marco │ select process() │ succeeded │ SELECT 1 │ 2023-02-07 09:29:00.015168+01 │ 2023-02-07 09:29:00.832308+01 │ │ 10 │ 4321 │ 2603 │ postgres │ marco │ select process() │ succeeded │ SELECT 1 │ 2023-02-07 09:28:00.011965+01 │ 2023-02-07 09:28:01.420901+01 │ │ 10 │ 4320 │ 2602 │ postgres │ marco │ select process() │ failed │ server restarted │ 2023-02-07 09:27:00.011833+01 │ 2023-02-07 09:27:00.72121+01 │ │ 9 │ 4320 │ 2602 │ postgres │ marco │ select do_stuff() │ failed │ job canceled │ 2023-02-07 09:26:00.011833+01 │ 2023-02-07 09:26:00.22121+01 │ └───────┴───────┴─────────┴──────────┴──────────┴───────────────────┴───────────┴──────────────────┴───────────────────────────────┴───────────────────────────────┘ (10 rows)
Записи в таблице не очищаются автоматически, но каждый пользователь, который может планировать задания cron, также имеет разрешение удалять свои собственные записи cron.job_run_details.
Особенно когда у вас есть задания, которые выполняются каждые несколько секунд, может быть хорошей идеей регулярно выполнять очистку, что легко можно сделать с помощью самого pg_cron:
-- Delete old cron.job_run_details records of the current user every day at noon
SELECT cron.schedule('delete-job-run-details', '0 12 * * *', $$DELETE FROM cron.job_run_details WHERE end_time < now() - interval '7 days'$$);
Если вы не хотите использовать
cron.job_run_details вообще, то вы можете добавить
cron.log_run = off в
postgresql.conf.
F.31.6.2. Другие параметры журналирования cron #
Если параметр cron.log_statement настроен,
задания будут журналироваться перед выполнением.
Параметр cron.log_min_messages управляет
минимальным уровнем сообщений, которые будут записываться.