pg_cron
本文介紹了pg_cron插件的背景、原理以及示例等內(nèi)容。
背景信息
定時(shí)任務(wù)是一種在預(yù)定的時(shí)間點(diǎn)或時(shí)間間隔內(nèi)自動(dòng)執(zhí)行的任務(wù)。定時(shí)任務(wù)通常由一個(gè)調(diào)度器負(fù)責(zé)管理,根據(jù)預(yù)定的時(shí)間規(guī)則觸發(fā)任務(wù)的執(zhí)行。常見的時(shí)間規(guī)則包括每天的特定時(shí)間點(diǎn)、每周的特定日期和時(shí)間、每月的特定日期和時(shí)間等。調(diào)度器還可以根據(jù)任務(wù)的需要設(shè)置任務(wù)的執(zhí)行次數(shù)和重復(fù)間隔。
定時(shí)任務(wù)的應(yīng)用場(chǎng)景非常廣泛:
在服務(wù)器端,定時(shí)任務(wù)常用于定期執(zhí)行后臺(tái)任務(wù)、生成報(bào)告、清理垃圾數(shù)據(jù)等。
在客戶端,定時(shí)任務(wù)可以用于更新數(shù)據(jù)、提醒用戶、執(zhí)行自動(dòng)化操作等。
無(wú)論是在服務(wù)器端還是客戶端,定時(shí)任務(wù)都可以減輕人工操作的負(fù)擔(dān),提升工作效率。
pg_cron
是PolarDB PostgreSQL版(兼容Oracle)支持的一款第三方插件,提供了在PolarDB PostgreSQL版(兼容Oracle)中通過(guò)cron語(yǔ)法定時(shí)執(zhí)行SQL的能力。用戶可以通過(guò)SQL語(yǔ)句創(chuàng)建定時(shí)任務(wù),并在指定的時(shí)間點(diǎn)或時(shí)間間隔內(nèi)自動(dòng)執(zhí)行任務(wù)。
pg_cron
的優(yōu)勢(shì)如下:
簡(jiǎn)單易用:執(zhí)行SQL語(yǔ)句即可創(chuàng)建、調(diào)度和管理任務(wù),無(wú)需額外的編程或配置。
靈活的調(diào)度選項(xiàng):支持按分鐘、小時(shí)、日期、星期、月份及其組合進(jìn)行定時(shí)調(diào)度。
庫(kù)級(jí)別的任務(wù)管理:定時(shí)任務(wù)保存在數(shù)據(jù)庫(kù)中,可以跨多個(gè)數(shù)據(jù)庫(kù)共享和管理任務(wù)。
并發(fā)任務(wù)執(zhí)行:支持同時(shí)執(zhí)行多個(gè)任務(wù),提高任務(wù)執(zhí)行效率。
可靠性和容錯(cuò)性:提供錯(cuò)誤處理和容錯(cuò)機(jī)制,確保任務(wù)的正確執(zhí)行并提供相應(yīng)的日志記錄。
pg_cron
為數(shù)據(jù)庫(kù)管理員和開發(fā)人員提供了一種簡(jiǎn)單而強(qiáng)大的方式來(lái)自動(dòng)化執(zhí)行重復(fù)性任務(wù)。例如,備份數(shù)據(jù)、生成報(bào)告、定期清理等,從而提升數(shù)據(jù)庫(kù)的管理和開發(fā)效率。
原理介紹
定時(shí)任務(wù)信息維護(hù)
所有的定時(shí)任務(wù)將會(huì)被存儲(chǔ)在cron.job
表中,用戶可以通過(guò)SQL函數(shù)接口新增或刪除定時(shí)任務(wù)。
pg_cron
通過(guò)維護(hù)JOB LIST和TASK LIST兩個(gè)列表進(jìn)行后臺(tái)調(diào)度和任務(wù)執(zhí)行。數(shù)據(jù)庫(kù)啟動(dòng)時(shí),根據(jù)cron.job
表中的任務(wù)列表構(gòu)造JOB LIST和TASK LIST;后續(xù)任務(wù)列表有更新時(shí),通過(guò)觸發(fā)器cron.job_cache_invalidate
刷新列表保持JOB LIST和TASK LIST與cron.job
表實(shí)時(shí)一致,確保任務(wù)能夠得到正確調(diào)度和執(zhí)行。
定時(shí)任務(wù)調(diào)度執(zhí)行
WAITING(等待):默認(rèn)狀態(tài)。如果條件不滿足(非激活狀態(tài)/計(jì)劃時(shí)間還未到),則跳過(guò)該任務(wù)的調(diào)度;如果條件滿足,則進(jìn)入START狀態(tài)。
START(啟動(dòng)):構(gòu)建任務(wù)的連接信息,并進(jìn)行連接測(cè)試。如果連接成功,則進(jìn)入CONNECTING狀態(tài);否則進(jìn)入ERROR狀態(tài)。
CONNECTING(連接):檢查任務(wù)是否激活,連接是否正常。如果所有條件都滿足,則進(jìn)入SENDING狀態(tài);否則進(jìn)入ERROR狀態(tài)。
SENDING(發(fā)送):檢查任務(wù)是否激活,連接是否正常。如果所有條件滿足,將定時(shí)任務(wù)文本發(fā)送至PolarDB PostgreSQL版(兼容Oracle)服務(wù)器,進(jìn)入RUNNING狀態(tài);否則進(jìn)入ERROR狀態(tài)。
RUNNING(運(yùn)行):檢查任務(wù)是否激活,連接是否正常。如果所有條件都滿足,接收傳回的任務(wù)結(jié)果并進(jìn)入DONE狀態(tài);否則跳出等待進(jìn)入ERROR狀態(tài)。
ERROR(錯(cuò)誤):任務(wù)失敗,重置連接信息并進(jìn)入DONE狀態(tài)。
DONE(完成):任務(wù)完成,重置任務(wù)信息并重新進(jìn)入WAITING狀態(tài)。
函數(shù)列表
出于安全性考慮,只能以高權(quán)限用戶通過(guò)下列函數(shù)操作
cron.job
表;普通用戶只有cron.job
表的查看權(quán)限。所有定時(shí)任務(wù)都儲(chǔ)存于
postgres
數(shù)據(jù)庫(kù)中,對(duì)定時(shí)任務(wù)的操作需要連接到postgres
數(shù)據(jù)庫(kù)進(jìn)行操作。定時(shí)任務(wù)執(zhí)行的時(shí)間為GMT時(shí)間(格林威治標(biāo)準(zhǔn)時(shí)間),請(qǐng)注意換算時(shí)間。
添加定時(shí)任務(wù)
語(yǔ)法
cron.schedule (
job_name TEXT,
schedule TEXT,
command TEXT
);
參數(shù)說(shuō)明
參數(shù) | 說(shuō)明 |
job_name | 任務(wù)名稱,可以默認(rèn)為空。 |
schedule | 任務(wù)計(jì)劃周期,格式為標(biāo)準(zhǔn) |
command | 任務(wù)內(nèi)容,格式為 |
在指定數(shù)據(jù)庫(kù)中添加定時(shí)任務(wù)
語(yǔ)法
cron.schedule_in_database (
job_name TEXT,
schedule TEXT,
command TEXT,
db_name TEXT
);
參數(shù)說(shuō)明
參數(shù) | 說(shuō)明 |
job_name | 任務(wù)名稱。 |
schedule | 任務(wù)計(jì)劃周期,格式為標(biāo)準(zhǔn) |
command | 任務(wù)內(nèi)容,格式為 |
db_name | 任務(wù)執(zhí)行的目標(biāo)數(shù)據(jù)庫(kù)。 |
修改定時(shí)任務(wù)
語(yǔ)法
cron.alter_job (
job_id BIGINT,
schedule TEXT DEFAULT NULL,
command TEXT DEFAULT NULL,
db_name TEXT DEFAULT NULL,
active BOOLEAN DEFAULT NULL
);
參數(shù)說(shuō)明
參數(shù) | 說(shuō)明 |
job_id | 待修改的任務(wù)ID。 |
schedule | 修改后的任務(wù)計(jì)劃。 |
command | 修改后的任務(wù)內(nèi)容。 |
db_name | 修改后的任務(wù)執(zhí)行數(shù)據(jù)庫(kù)。 |
active | 修改后任務(wù)是否處于激活狀態(tài)(正常運(yùn)行)。 |
刪除定時(shí)任務(wù)
語(yǔ)法
cron.unschedule(job_id BIGINT);
cron.unschedule(job_name TEXT);
參數(shù)說(shuō)明
參數(shù) | 說(shuō)明 |
job_id | 待刪除任務(wù)ID。 |
name | 待刪除任務(wù)名稱。 |
使用指南
出于安全性考慮,只能以高權(quán)限用戶執(zhí)行以下操作。
創(chuàng)建插件
連接數(shù)據(jù)庫(kù)并執(zhí)行以下命令,創(chuàng)建pg_cron
插件。
CREATE EXTENSION pg_cron;
新增定時(shí)任務(wù)
執(zhí)行以下命令,為db01
數(shù)據(jù)庫(kù)創(chuàng)建一個(gè)名為task1
的任務(wù),函數(shù)將返回任務(wù)ID。
SELECT cron.schedule_in_database('task1', '* * * * *', 'SELECT 1', 'db01');
結(jié)果顯示如下:
schedule_in_database
----------------------
1
(1 row)
查看定時(shí)任務(wù)列表
執(zhí)行以下命令,查看定時(shí)任務(wù)列表。
SELECT * FROM cron.job;
結(jié)果顯示如下:
jobid | schedule | command | nodename | nodeport | database | username | active | jobname
-------+-----------+----------+----------+----------+----------+----------+--------+---------
1 | * * * * * | SELECT 1 | /tmp | 39361 | db01 | u1 | t | task1
(1 row)
查看定時(shí)任務(wù)執(zhí)行歷史
執(zhí)行以下命令,查看定時(shí)任務(wù)執(zhí)行歷史。
SELECT * FROM cron.job_run_details;
結(jié)果顯示如下:
jobid | runid | job_pid | database | username | command | status | return_message | start_time | end_time
-------+-------+---------+----------+----------+----------+-----------+----------------+-------------------------------+-------------------------------
1 | 1 | 4152316 | db01 | u1 | SELECT 1 | succeeded | 1 row | 2023-10-19 03:55:00.020442+00 | 2023-10-19 03:55:00.021512+00
1 | 2 | 4152438 | db01 | u1 | SELECT 1 | succeeded | 1 row | 2023-10-19 03:56:00.006468+00 | 2023-10-19 03:56:00.006822+00
(2 rows)
刪除定時(shí)任務(wù)
執(zhí)行以下命令,刪除定時(shí)任務(wù)。
SELECT cron.unschedule('task1');
結(jié)果顯示如下:
unschedule
------------
t
(1 row)
刪除插件
執(zhí)行以下命令,刪除pg_cron
插件。
DROP EXTENSION pg_cron;
時(shí)間規(guī)則示例
pg_cron
使用標(biāo)準(zhǔn)的cron語(yǔ)法,*
表示每間隔指定單位時(shí)間運(yùn)行,指定數(shù)字表示間隔該數(shù)字單位時(shí)間運(yùn)行。
┌───────────── 分鐘 (0 - 59)
│ ┌────────────── 小時(shí) (0 - 23)
│ │ ┌─────────────── 日期 (1 - 31)
│ │ │ ┌──────────────── 月份 (1 - 12)
│ │ │ │ ┌───────────────── 一周中的某一天 (0 - 6) (0到6表示周日到下周六,
│ │ │ │ │ 7 也表示周日)
* * * * *
在每周六3:30 AM(GMT 時(shí)間)刪除過(guò)期數(shù)據(jù)。
SELECT cron.schedule('30 3 * * 6', $$DELETE FROM events WHERE event_time < now() - interval '1 week'$$);
在每天10:00 AM(GMT 時(shí)間)執(zhí)行
VACUUM
。SELECT cron.schedule('0 10 * * *', 'VACUUM;');
每分鐘執(zhí)行SQL。
SELECT cron.schedule('* * * * *', 'SELECT 1;');
每小時(shí)的23分鐘執(zhí)行SQL。
SELECT cron.schedule('23 * * * *', 'SELECT 1;');
每個(gè)月的4號(hào)執(zhí)行SQL。
SELECT cron.schedule('* * 4 * *', 'SELECT 1;');