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