
# 使用pg_cron插件
#### 简介
pg_cron扩展是一个使用cron语法的定时任务调度程序。与常规cron使用相同的语法，但允许直接从数据库执行PostgreSQL命令。更多信息，请参见[pg_cron官方文档](https://github.com/citusdata/pg_cron)。
#### 支持的版本说明
PostgreSQL 12及以上版本的最新小版本支持该插件。可通过以下SQL语句查询当前实例支持该插件的版本：
```
SELECT * FROM pg_available_extension_versions WHERE name = 'pg_cron';
```
如果不支持，可通过[升级内核小版本](https://support.huaweicloud.com/usermanual-rds-pg/rds_pg_05_0003.html)或者[使用转储与还原升级大版本](https://support.huaweicloud.com/usermanual-rds-pg/rds_09_0053.html)使用该插件。
RDS for PostgreSQL实例支持的插件，具体请参见[支持的插件列表](https://support.huaweicloud.com/usermanual-rds-pg/rds_09_0045.html)。
#### 插件介绍
标准cron语法，\*表示每个时间段运行，特定数字表示仅在此时间。
```
┌───────────── min (0 - 59)  
   │ ┌────────────── hour (0 - 23)  
   │ │ ┌─────────────── day of month (1 - 31)  
   │ │ │ ┌──────────────── month (1 - 12)  
   │ │ │ │ ┌───────────────── day of week (0 - 6) (0 to 6 are Sunday to  
   │ │ │ │ │                                   Saturday, or use names; 7 is also Sunday)  
   │ │ │ │ │  
   │ │ │ │ │
```
例如每周六9:30 AM（GMT）的语法为：
```
30 9 * * 6
```
#### 注意事项
- pg_cron需要后台守护进程，因此启动数据库前，需要将pg_cron放到shared_preload_libraries中。
- 定时任务不会在备机上运行，但当备机升主后，定时任务会自动启动。
- 定时任务会以任务创建者的权限执行。
- 定时任务使用GMT时间执行。
- 一个实例可以并行运行多个任务，但同一时间某个任务仅能运行一个。
- 某个任务，需要等待前一个定时任务结束，那么该任务会进入等待队列，且会在前一个任务结束后尽快启动。
- 使用前，需要将cron.database_name修改为创建定时任务的数据库，并且只能设为单个数据库，不支持设置多个数据库。
 
#### 插件安装
1. 在实例列表，单击实例名称，进入"概览"页面。
2. 选择"插件管理"，将pg_cron添加到shared_preload_libraries参数中。
   图1插件管理   
   ![](https://support.huaweicloud.com/usermanual-rds-pg/zh-cn_image_0000002248942833.png "点击放大") 
3. 重启实例，使shared_preload_libraries参数值生效。
   图2添加完成   
   ![](https://support.huaweicloud.com/usermanual-rds-pg/zh-cn_image_0000002213822884.png "点击放大") 
4. 如果插件安装的数据库不是默认的postgres库，需要修改参数"cron.database_name"。
   该pg_cron插件在哪个库使用，就需要将该参数"cron.database_name"的值修改为对应的数据库名称。例如：需要在test_db库安装使用，就需要修改参数"cron.database_name"值为test_db。
   图3修改参数值   
   ![](https://support.huaweicloud.com/usermanual-rds-pg/zh-cn_image_0000002213663116.png "点击放大")
   ![](https://support.huaweicloud.com/usermanual-rds-pg/public_sys-resources/note_3.0-zh-cn.png)
   修改参数"cron.database_name"的值后，需要重启实例使参数值生效。
   
5. 安装pg_cron插件。
   - 通过界面安装pg_cron
     在插件管理页面，选择对应的数据库，搜索pg_cron，单击"安装"。
     图4安装pg_cron   
     ![](https://support.huaweicloud.com/usermanual-rds-pg/zh-cn_image_0000002213822888.png "点击放大") 
   
   - 通过SQL安装pg_cron 登录到对应的数据库，执行如下SQL创建插件：
     ```
     CREATE EXTENSION IF NOT EXISTS pg_cron;
     ```
     
    
 
#### 基本使用
创建任务：
```
-- 任务1：每周六上午3:30(GMT)，删除旧数据 
SELECT cron.schedule('30 3 * * 6', $$DELETE FROM events WHERE event_time < now() - interval '1 week'$$);  
-- 任务2：每天上午 10:00(GMT)，执行vacuum，任务以nightly-vacuum为命名。
SELECT cron.schedule('nightly-vacuum', '0 10 * * *', 'VACUUM');
```
#### 进阶使用（对postgres以外的数据库设置定时任务）
前提：在postgres库中已经安装pg_cron插件、已提前创建test_db数据库，需要在test_db设置定时任务。
1. 登录postgres库。
2. 创建定时任务。
   ```
   SELECT cron.schedule('create', '10 * * * *', 'create table test (a int);');
   SELECT cron.schedule('insert', '15 * * * *', 'insert into test values(1);');
   SELECT cron.schedule('drop', '20 * * * *', 'drop table test;');
   ```
   ![](https://support.huaweicloud.com/usermanual-rds-pg/public_sys-resources/note_3.0-zh-cn.png)
   定时任务名称不能相同，否则会被覆盖。
   
3. 将定时任务设置为想要执行定时任务的库test_db。
   ```
   UPDATE cron.job SET database = 'test_db' WHERE jobid = 1;
   UPDATE cron.job SET database = 'test_db' WHERE jobid = 2;
   UPDATE cron.job SET database = 'test_db' WHERE jobid = 3;
   ```
   *jobid*可通过如下命令查询：
   ```
   postgres=> select * from cron.job;
    jobid |  schedule  |           command           | nodename  | nodeport | database  | username | active | jobname 
   -------+------------+-----------------------------+-----------+----------+-----------+----------+--------+---------
        1 | 10 * * * * | create table test (a int);  | localhost |     5432 | postgres  | root     | t      | create
        2 | 15 * * * * | insert into test values(1); | localhost |     5432 | postgres  | root     | t      | insert
        3 | 20 * * * * | drop table test;            | localhost |     5432 | postgres  | root     | t      | drop
   ```
   
4. 查看修改结果，会发现database字段为test_db，即该任务执行的数据库为test_db。
   ```
   postgres=> select * from cron.job;
    jobid |  schedule  |           command           | nodename  | nodeport | database  | username | active | jobname 
   -------+------------+-----------------------------+-----------+----------+-----------+----------+--------+---------
        1 | 10 * * * * | create table test (a int);  | localhost |     5432 | test_db   | root     | t      | create
        2 | 15 * * * * | insert into test values(1); | localhost |     5432 | test_db   | root     | t      | insert
        3 | 20 * * * * | drop table test;            | localhost |     5432 | test_db   | root     | t      | drop
   ```
   
5. 验证定时任务是否执行成功。
   - 在日志中查看是否有对应定时任务执行成功。
     图5查看日志   
     ![](https://support.huaweicloud.com/usermanual-rds-pg/zh-cn_image_0000002248782941.png "点击放大") 
   
   - 在test_db库执行查询，查看test表已经创建成功。
     图6查看库   
     ![](https://support.huaweicloud.com/usermanual-rds-pg/zh-cn_image_0000002248782937.png "点击放大") 
    
6. 如果不想再使用该定时任务，根据在[4]中查询出的结果，执行以下SQL删除任务。
   - 通过定时任务jobid删除
     ```
     SELECT cron.unschedule(1);
     ```
     
   
   - 通过定时任务名称删除
     ```
     SELECT cron.unschedule('create');
     ```
     
    
 
#### pg_cron插件相关的参数
表1参数说明 
| 参数名                         | 功能                              | 默认值       | 需要重启 |
|:---|:---|:---|:---|
| cron.database_name          | 定时任务元信息所在的数据库。                  | postgres  | 是    |
| cron.log_statement          | 执行任务前，是否将SQL打印到日志。              | true      | 是    |
| cron.log_run                | 是否将任务的执行信息存储到job_run_details表中。 | true      | 是    |
| cron.host                   | 要执行定时任务的host名。                  | localhost | 是    |
| cron.use_background_workers | 使用后台work进程，而非客户端连接执行任务。         | false     | 是    |
| cron.max_running_jobs       | 可以同时运行的job数量。                   | 5         | 是    |
   
