

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 使用 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://aws.amazon.com/blogs/database/schedule-jobs-with-pg_cron-on-your-amazon-rds-for-postgresql-or-amazon-aurora-for-postgresql-databases/)

**注意**  
`pg_cron` 延伸版本會在 pg\$1available\$1extensions 檢視中顯示為兩個數字的版本，例如 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. 修改與 PostgreSQL 資料庫執行個體關聯的自訂參數群組，並將 `pg_cron` 新增至 `shared_preload_libraries` 參數值。
   + 如果 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 資料庫執行個體建立 RDS 時使用了預設設定，請以使用者 `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>

自動資料清理功能可處理大多數情況下的清理維護。但是，您可能想要在您選定的時間來排定清理特定的資料表。

另請參閱 [在 Amazon RDS for PostgreSQL 上使用 PostgreSQL 自動清空](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` 參數設定為關閉。`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` 擴充功能行為的參數清單。


| 參數 | Description | 
| --- | --- | 
| 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.aws.amazon.com/zh_tw/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.aws.amazon.com/zh_tw/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)。   | 