pg_timetable: PostgreSQL 作业调度器

三月 28, 2025

摘要pg_timetable程序是 PostgreSQL 的一个高级作业调度工具。

目录

pg_timetable 简介

在数据库管理中,作业调度一直发挥着重要作用。对于 PostgreSQL 而言,其广受欢迎的作业调度器有 PgAgent 和 pg_cron。然而,还有一个名为 pg_timetable 的作业调度器,它完全由数据库驱动,并提供了一些先进的概念。在本文中,我们将重点介绍 pg_timetable 的一些主要特性、安装方法和使用案例。

主要特性

  • 完全由数据库驱动的配置
  • 基于 PostgreSQL 服务器时区,类似 Cron 的调度风格
  • 内置发送邮件等任务
  • 完全支持由数据库驱动的日志记录
  • 任务可设置为链式执行
  • 任务链中可包含内置命令、SQL 语句和可执行文件
  • 可向任务链 / 任务传递参数

安装

目前,安装和运行 pg_timetable 有两种方式:

  • 容器安装。相关内容请参考此页面
  • 本地安装,即从源代码构建。这里我们将讨论这种方法。

1. 在您的系统上下载并安装 GO

2. 克隆 pg_timetable 仓库

$ git clone https://github.com/cybertec-postgresql/pg_timetable.git
$ cd pg_timetable

3. 运行 pg_timetable

$ go run main.go --dbname=dbname --clientname=worker001 --user=scheduler --password=strongpassword

4. 或者,构建一个二进制文件并运行它:

$ go build
$ ./pg_timetable --dbname=dbname --clientname=worker001 --user=scheduler --password=strongpassword

使用 pg_timetable 演示作业调度

在本用例中,将会展示如何使用 pg_timetable 作为调度器来安排一个作业,该作业会在每天午夜 12 点刷新物化视图。

1. 下载 pg_timetable 可执行文件(遵循上述安装部分中的步骤 2)。

2. 确保 PostgreSQL 服务器已启动并运行,并且拥有一个对目标数据库具有 CREATE 权限的角色,例如:

CREATE ROLE scheduler PASSWORD '***********';
GRANT CREATE ON DATABASE postgres TO scheduler;

CREATE TABLE t_demo (grp int, data numeric);

INSERT INTO t_demo SELECT 1, random()
FROM generate_series(1, 5000000);

CREATE MATERIALIZED VIEW mat_view AS
SELECT grp, avg(data), count(*)
FROM t_demo
GROUP BY 1;

ALTER MATERIALIZED VIEW mat_view OWNER TO scheduler;
GRANT SELECT ON mat_view TO scheduler;

SELECT * FROM mat_view;
 grp |           avg            | count
-----+--------------------------+---------
 1   | 0.5001807958659610956005 | 5000000
(1 row)

INSERT INTO t_demo
  SELECT 2, random()
    FROM generate_series(1, 5000000);

3. 创建一个新作业,以在 Postgres 服务器时区的每晚 12 点刷新物化视图:

SELECT timetable.add_job('refresh-matview', '0 12 * * *', 'REFRESH MATERIALIZED VIEW public.mat_view');
 add_job
---------
 1
(1 row)

4. 运行 pg_timetable:

$ ./pg_timetable --dbname=postgres --clientname=worker001 --user=scheduler --password=********
2024-09-09 11:59:20.929 [INFO] [sid:697146069] Starting new session...
2024-09-09 11:59:20.941 [INFO] Database connection established
2024-09-10 12:00:00.961 [INFO] Accepting asynchronous chains execution requests...
2024-09-10 12:00:00.970 [INFO] [count:0] Retrieve scheduled chains to run @reboot
2024-09-10 12:00:00.991 [INFO] [count:3] Retrieve scheduled chains to run
2024-09-10 12:00:00.994 [INFO] [count:0] Retrieve interval chains to run
2024-09-10 12:00:00.019 [INFO] [chain:1] Starting chain
2024-09-10 12:00:00.722 [INFO] [chain:1] [task:1] [txid:2613] Starting task
2024-09-10 12:00:00.074 [INFO] [chain:1] [task:1] [txid:2613] Starting task
2024-09-10 12:00:00.141 [INFO] [chain:1] [task:1] [txid:2613] Closing remote session
2024-09-10 12:00:00.141 [INFO] [chain:1] [task:1] [txid:2613] Task executed successfully
2024-09-10 12:00:00.185 [INFO] [chain:1] [txid:2613] Chain executed successfully

在首次启动 pg_timetable 时,会创建一个必要的 timetable 模式。作为参考,以下是表结构:

postgres=# \dn
   List of schemas
    Name   | Owner
-----------+-----------
 public    | postgres
 timetable | scheduler
(2 rows)

postgres=# set search_path to timetable ;

postgres=# \dt
List of relations
  Schema   |      Name      | Type  | Owner
-----------+----------------+-------+-----------
 timetable | active_chain   | table | scheduler
 timetable | active_session | table | scheduler
 timetable | chain          | table | scheduler
 timetable | execution_log  | table | scheduler
 timetable | log            | table | scheduler
 timetable | migration      | table | scheduler
 timetable | parameter      | table | scheduler
 timetable | task           | table | scheduler
(8 rows)

5. 从数据库日志中可以观察到,物化视图已按计划刷新。

数据库日志的输出:

2024-09-10 12:00:00 UTC [14334] LOG:  statement: REFRESH MATERIALIZED VIEW public.mat_view

使用 psql 连接到数据库,执行查询:

SELECT * FROM mat_view;
 grp |             avg           |  count
-----+---------------------------+---------
  1  | 0.5001807958659610956005  | 5000000
  2  | 0.50000009110202547559215 | 5000000
(2 rows)

以下是 pg_timetable 系统表的内容:

select * from active_session ;
 client_pid | server_pid | client_name |          started_at
------------+------------+-------------+-----------------------------
 697146069  |  20137     |  worker001  | 2024-09-10 11:59:205672+00
(1 row)
select * from chain;
-[ RECORD 1 ]--------+--------------------
 chain_id            | 1
 chain_name          | refresh-matview
 run_at              | 0 12 * * *
 max_instances       |
 timeout             | 0
 live                | t
 self_destruct       | f
 exclusive_execution | f
 client_name         |
 on_error            |
select * from execution_log where chain_id=1;
-[ RECORD 1 ]-+------------------------------------------
 chain_id     | 1
 task_id      | 1
 txid         | 2613
 last_run     | 2024-09-10 12:00:00.137404+00
 finished     | 2024-09-10 12:00:00.586543+00
 pid          | 697146069
 returncode   | 0
 kind         | SQL
 command      | REFRESH MATERIALIZED VIEW public.mat_view
 output       | REFRESH MATERIALIZED VIEW
 client_name  | worker001

总之,pg_timetable 是开源的,可供所有人免费使用。其主要优点包括:pg_timetable 是用 GO 编写的独立进程,它像任何其他客户端程序一样连接到 PostgreSQL。因此,如果调度器崩溃,不会对服务器造成损害。pg_timetable 提供了多种内置任务,有助于您轻松灵活地组合这些操作。此外,pg_timetable 是用 GO 实现的,因此是一个可直接启动的可执行文件。所以,在安装过程中无需担心库或依赖项的问题。

了解更多

pg_timetable 项目