

# 使用 PostgreSQL pg\$1cron 扩展计划维护
<a name="PostgreSQL_pg_cron"></a>

您可以使用 PostgreSQL `pg_cron` 扩展来计划 PostgreSQL 数据库中的维护命令。有关扩展的更多信息，请参阅 pg\$1cron 文档中的[什么是 pg\$1cron？](https://github.com/citusdata/pg_cron) 

RDS for PostgreSQL 引擎版本 12.5 及更高版本支持 `pg_cron` 扩展。

要了解有关使用 `pg_cron` 的更多信息，请参阅[在 RDS for PostgreSQL 或 Aurora PostgreSQL 兼容版数据库上使用 pg\$1cron 计划任务](https://www.amazonaws.cn/blogs/database/schedule-jobs-with-pg_cron-on-your-amazon-rds-for-postgresql-or-amazon-aurora-for-postgresql-databases/)。

**注意**  
在 pg\$1available\$1extensions 视图中，`pg_cron` 扩展版本显示为两位数的版本，例如 1.6。虽然在某些情况下您可能会看到三位数的版本，例如 1.6.4 或 1.6.5，但在执行扩展升级时必须指定两位数的版本。

**Topics**
+ [

## 设置 pg\$1cron 扩展
](#PostgreSQL_pg_cron.enable)
+ [

## 授予数据库用户使用 pg\$1cron 的权限
](#PostgreSQL_pg_cron.permissions)
+ [

## 计划 pg\$1cron 作业
](#PostgreSQL_pg_cron.examples)
+ [

## pg\$1cron 扩展的参考
](#PostgreSQL_pg_cron.reference)

## 设置 pg\$1cron 扩展
<a name="PostgreSQL_pg_cron.enable"></a>

按如下方式设置 `pg_cron` 扩展：

1. 通过向 `shared_preload_libraries` 参数值添加 `pg_cron`，修改与 PostgreSQL 数据库实例关联的自定义参数组。
   + 如果 RDS for PostgreSQL 数据库实例使用 `rds.allowed_extensions` 参数显式列出可安装的扩展，则需要将 `pg_cron` 扩展添加到列表中。只有某些版本的 RDS for PostgreSQL 支持 `rds.allowed_extensions` 参数。原定设置情况下，允许使用所有可用的扩展。有关更多信息，请参阅 [限制 PostgreSQL 扩展的安装](PostgreSQL.Concepts.General.FeatureSupport.Extensions.md#PostgreSQL.Concepts.General.FeatureSupport.Extensions.Restriction)。

   重新启动 PostgreSQL 数据库实例，以使对参数组的更改生效。要了解有关使用参数组的更多信息，请参阅[在 Amazon RDS 中修改数据库参数组中的参数](USER_WorkingWithParamGroups.Modifying.md)。

1. 重新启动 PostgreSQL 数据库实例后，使用具有 `rds_superuser` 权限的账户运行以下命令。例如，如果在创建 RDS for PostgreSQL 数据库实例时使用默认设置，请以用户 `postgres` 身份进行连接，然后创建扩展。

   ```
   CREATE EXTENSION pg_cron;
   ```

   `pg_cron` 调度程序是在名为 `postgres` 的默认 PostgreSQL 数据库中设置的。这些 `pg_cron` 对象是在此 `postgres` 数据库中创建的，所有调度操作都在此数据库中运行。

1. 您可以使用默认设置，也可以计划作业在 PostgreSQL 数据库实例的其他数据库中运行。要为 PostgreSQL 数据库实例中的其他数据库计划作业，请参阅 [为原定设置数据库以外的数据库计划 cron 任务](#PostgreSQL_pg_cron.otherDB) 中的示例。

## 授予数据库用户使用 pg\$1cron 的权限
<a name="PostgreSQL_pg_cron.permissions"></a>

安装 `pg_cron` 扩展需要 `rds_superuser` 权限。但是，可以（由 `pg_cron` 组/角色的成员）将使用 `rds_superuser` 的权限授予其他数据库用户，以便他们可以计划自己的任务。我们建议您仅在需要时才授予对 `cron` 架构的权限，前提是它可以改进生产环境中的操作。

要在 `cron` 架构中授予数据库用户权限，请运行以下命令：

```
postgres=> GRANT USAGE ON SCHEMA cron TO db-user;
```

这向 *db-user* 授予访问 `cron` 架构的权限，以便为他们有权限访问的对象计划 cron 任务。如果数据库用户没有权限，则在将错误消息发布到 `postgresql.log` 文件后，任务会失败，如下所示：

```
2020-12-08 16:41:00 UTC::@:[30647]:ERROR: permission denied for table table-name
2020-12-08 16:41:00 UTC::@:[27071]:LOG: background worker "pg_cron" (PID 30647) exited with exit code 1
```

换言之，请确保被授予对 `cron` 架构的权限的数据库用户也对他们计划安排的对象（表、架构等）拥有权限。

cron 任务的详细信息及其成功或失败情况也在 `cron.job_run_details` 表中捕获。有关更多信息，请参阅 [用于计划任务和捕获状态的表](#PostgreSQL_pg_cron.tables)。

## 计划 pg\$1cron 作业
<a name="PostgreSQL_pg_cron.examples"></a>

以下各节介绍了如何使用 `pg_cron` 作业安排各种管理任务。

**注意**  
创建 `pg_cron` 任务时，请检查 `max_worker_processes` 设置是否大于 `cron.max_running_jobs` 的数量。如果 `pg_cron` 任务耗尽后台工作进程，它将失败。原定设置的 `pg_cron` 任务数量为 `5`。有关更多信息，请参阅 [用于管理 pg\$1cron 扩展的参数](#PostgreSQL_pg_cron.parameters)。

**Topics**
+ [

### 对表执行清理操作
](#PostgreSQL_pg_cron.vacuum)
+ [

### 清除 pg\$1cron 历史记录表
](#PostgreSQL_pg_cron.job_run_details)
+ [

### 仅将错误记录到 postgresql.log 文件中
](#PostgreSQL_pg_cron.log_run)
+ [

### 为原定设置数据库以外的数据库计划 cron 任务
](#PostgreSQL_pg_cron.otherDB)

### 对表执行清理操作
<a name="PostgreSQL_pg_cron.vacuum"></a>

Autovacuum 在大多数情况下处理清理维护。但是，您可能希望在选择的时间计划对特定表执行清理操作。

另请参阅[在 Amazon RDS for PostgreSQL 上使用 PostgreSQL autovacuum](Appendix.PostgreSQL.CommonDBATasks.Autovacuum.md)。

以下示例介绍了使用 `cron.schedule` 函数设置作业，以便每天 22:00 (GMT) 在特定表上使用 `VACUUM FREEZE`。

```
SELECT cron.schedule('manual vacuum', '0 22 * * *', 'VACUUM FREEZE pgbench_accounts');
 schedule
----------
1
(1 row)
```

运行上述示例之后，您可以按如下方式检查 `cron.job_run_details` 表中的历史记录。

```
postgres=> SELECT * FROM cron.job_run_details;
jobid  | runid | job_pid | database | username | command                        | status    | return_message | start_time                    | end_time
-------+-------+---------+----------+----------+--------------------------------+-----------+----------------+-------------------------------+-------------------------------
 1     | 1     | 3395    | postgres | adminuser| vacuum freeze pgbench_accounts | succeeded | VACUUM         | 2020-12-04 21:10:00.050386+00 | 2020-12-04 21:10:00.072028+00
(1 row)
```

下面的内容说明如何查询 `cron.job_run_details` 表以查看失败的任务。

```
postgres=> SELECT * FROM cron.job_run_details WHERE status = 'failed';
jobid | runid | job_pid | database | username | command                       | status | return_message                                   | start_time                    | end_time
------+-------+---------+----------+----------+-------------------------------+--------+--------------------------------------------------+-------------------------------+------------------------------
 5    | 4     | 30339   | postgres | adminuser| vacuum freeze pgbench_account | failed | ERROR: relation "pgbench_account" does not exist | 2020-12-04 21:48:00.015145+00 | 2020-12-04 21:48:00.029567+00
(1 row)
```

有关更多信息，请参阅 [用于计划任务和捕获状态的表](#PostgreSQL_pg_cron.tables)。

### 清除 pg\$1cron 历史记录表
<a name="PostgreSQL_pg_cron.job_run_details"></a>

`cron.job_run_details` 表包含 cron 作业的历史记录，随着时间的推移，这些历史记录可能会变得非常大。我们建议您计划清除此表的作业。例如，保留一周的条目可能足以进行故障排除。

以下示例使用 [cron.schedule](#PostgreSQL_pg_cron.schedule) 函数计划每天午夜运行以清除 `cron.job_run_details` 表的作业。这项工作只保留了过去七天的历史记录。使用您的 `rds_superuser` 账户计划作业，如下所示。

```
SELECT cron.schedule('0 0 * * *', $$DELETE 
    FROM cron.job_run_details 
    WHERE end_time < now() - interval '7 days'$$);
```

有关更多信息，请参阅 [用于计划任务和捕获状态的表](#PostgreSQL_pg_cron.tables)。

### 仅将错误记录到 postgresql.log 文件中
<a name="PostgreSQL_pg_cron.log_run"></a>

要防止向 `cron.job_run_details` 表中进行写入，请修改与 PostgreSQL 数据库实例关联的参数组，然后将 `cron.log_run` 参数设置为 off。`pg_cron` 扩展不再写入表，只会将错误捕获到 `postgresql.log` 文件中。有关更多信息，请参阅 [在 Amazon RDS 中修改数据库参数组中的参数](USER_WorkingWithParamGroups.Modifying.md)。

使用以下命令检查 `cron.log_run` 参数的值。

```
postgres=> SHOW cron.log_run;
```

有关更多信息，请参阅 [用于管理 pg\$1cron 扩展的参数](#PostgreSQL_pg_cron.parameters)。

### 为原定设置数据库以外的数据库计划 cron 任务
<a name="PostgreSQL_pg_cron.otherDB"></a>

`pg_cron` 的元数据全部保存在名为 `postgres` 的 PostgreSQL 默认数据库中。由于后台工件用于运行维护 cron 作业，因此您可以在 PostgreSQL 数据库实例中的任何数据库中计划作业。

**注意**  
只有具有 `rds_superuser` 角色或 `rds_superuser` 权限的用户才能列出数据库中的所有 cron 作业。其他用户只能在 `cron.job` 表中查看其自己的作业。

1. 在 cron 数据库中，以与平常使用 [cron.schedule](#PostgreSQL_pg_cron.schedule) 相同的方式计划作业。

   ```
   postgres=> SELECT cron.schedule('database1 manual vacuum', '29 03 * * *', 'vacuum freeze test_table');
   ```

1. 作为具有 `rds_superuser` 角色的用户，请更新刚创建的作业的数据库列，使其在 PostgreSQL 数据库实例中的另一个数据库中运行。

   ```
   postgres=> UPDATE cron.job SET database = 'database1' WHERE jobid = 106;
   ```

1.  通过查询 `cron.job` 表进行验证。

   ```
   postgres=> SELECT * FROM cron.job;
   jobid | schedule    | command                        | nodename  | nodeport | database | username  | active | jobname
   ------+-------------+--------------------------------+-----------+----------+----------+-----------+--------+-------------------------
   106   | 29 03 * * * | vacuum freeze test_table       | localhost | 8192     | database1| adminuser | t      | database1 manual vacuum
     1   | 59 23 * * * | vacuum freeze pgbench_accounts | localhost | 8192     | postgres | adminuser | t      | manual vacuum
   (2 rows)
   ```

**注意**  
在某些情况下，您可以添加打算在其他数据库上运行的 cron 作业。在这些情况下，在您更新正确的数据库列之前，该作业可能会尝试在默认数据库 (`postgres`) 中运行。如果用户名具有权限，则作业将在默认数据库中成功运行。

## pg\$1cron 扩展的参考
<a name="PostgreSQL_pg_cron.reference"></a>

您可以将以下参数、函数和表与 `pg_cron` 扩展搭配使用。有关更多信息，请参阅 pg\$1cron 文档中的[什么是 pg\$1cron？](https://github.com/citusdata/pg_cron)。

**Topics**
+ [

### 用于管理 pg\$1cron 扩展的参数
](#PostgreSQL_pg_cron.parameters)
+ [

### 函数参考：cron.schedule
](#PostgreSQL_pg_cron.schedule)
+ [

### 函数参考：cron.unschedule
](#PostgreSQL_pg_cron.unschedule)
+ [

### 用于计划任务和捕获状态的表
](#PostgreSQL_pg_cron.tables)

### 用于管理 pg\$1cron 扩展的参数
<a name="PostgreSQL_pg_cron.parameters"></a>

以下是用于控制 `pg_cron` 扩展行为的参数列表。


| 参数 | 说明 | 
| --- | --- | 
| cron.database\$1name |  保存 `pg_cron` 元数据的数据库。  | 
| cron.host |  要连接到 PostgreSQL 的主机名。您无法修改此值。  | 
| cron.log\$1run |  在 `job_run_details` 表中记录运行的每个任务。值为 `on` 或 `off`。有关更多信息，请参阅“[用于计划任务和捕获状态的表](#PostgreSQL_pg_cron.tables)”。  | 
| cron.log\$1statement |  在运行所有 cron 语句之前将其记入日志。值为 `on` 或 `off`。  | 
| cron.max\$1running\$1jobs |  可以同时运行的最大作业数。  | 
| cron.use\$1background\$1workers |  使用后台工作程序而不是客户端会话。您无法修改此值。  | 

使用以下 SQL 命令来显示这些参数及其值。

```
postgres=> SELECT name, setting, short_desc FROM pg_settings WHERE name LIKE 'cron.%' ORDER BY name;
```

### 函数参考：cron.schedule
<a name="PostgreSQL_pg_cron.schedule"></a>

此函数计划 cron 作业。作业最初是在默认 `postgres` 数据库中计划的。该函数返回一个表示作业标识符的 `bigint` 值。要计划作业在 PostgreSQL 数据库实例的其他数据库中运行，请参阅 [为原定设置数据库以外的数据库计划 cron 任务](#PostgreSQL_pg_cron.otherDB) 中的示例。

该函数有两种语法格式。

**语法**  

```
cron.schedule (job_name,
    schedule,
    command
);

cron.schedule (schedule,
    command
);
```

**参数**      
[\[See the AWS documentation website for more details\]](http://docs.amazonaws.cn/AmazonRDS/latest/UserGuide/PostgreSQL_pg_cron.html)

**示例**  

```
postgres=> SELECT cron.schedule ('test','0 10 * * *', 'VACUUM pgbench_history');
 schedule
----------
      145
(1 row)

postgres=> SELECT cron.schedule ('0 15 * * *', 'VACUUM pgbench_accounts');
 schedule
----------
      146
(1 row)
```

### 函数参考：cron.unschedule
<a name="PostgreSQL_pg_cron.unschedule"></a>

此函数删除 cron 作业。您可以指定 `job_name` 或 `job_id`。策略可以确保您是删除作业计划的拥有者。该函数返回一个布尔值，指示成功或失败。

该函数使用以下语法格式。

**语法**  

```
cron.unschedule (job_id);

cron.unschedule (job_name);
```

**参数**      
[\[See the AWS documentation website for more details\]](http://docs.amazonaws.cn/AmazonRDS/latest/UserGuide/PostgreSQL_pg_cron.html)

**示例**  

```
postgres=> SELECT cron.unschedule(108);
 unschedule
------------
 t
(1 row)

postgres=> SELECT cron.unschedule('test');
 unschedule
------------
 t
(1 row)
```

### 用于计划任务和捕获状态的表
<a name="PostgreSQL_pg_cron.tables"></a>

将以下各表用于计划 cron 作业和记录作业完成的方式。


| 表 | 描述 | 
| --- | --- | 
| cron.job |  包含有关每个计划作业的元数据。与此表的大多数交互应使用 `cron.schedule` 和 `cron.unschedule` 函数完成。  我们不建议直接授予对此表的更新或插入权限。这样做将允许用户更新 `username` 列，从而以 `rds-superuser` 身份运行。   | 
| cron.job\$1run\$1details |  包含过去运行的计划作业的历史信息。这对于调查运行的作业的状态、返回消息以及开始和结束时间非常有用。  为了防止此表无限增长，请定期清除此表。有关示例，请参阅[清除 pg\$1cron 历史记录表](#PostgreSQL_pg_cron.job_run_details)。   | 