PostgreSQL / EDB

Automatyzacja zadań w PostgreSQL z pg_cron

2025-02-19
Podziel się

pg_cron to rozszerzenie silnika bazodanowego PostgreSQL, umożliwiające definiowanie i wykonywanie cyklicznych zadań bezpośrednio w bazie danych. Działa jako harmonogram, bardzo podobny do tradycyjnego programu Cron z rodziny systemów Unix. Jest jednak całkowicie zintegrowany z PostgreSQL, co eliminuje konieczność korzystania z zewnętrznych narzędzi do harmonogramowania. Dzięki pg_cron administratorzy baz danych oraz deweloperzy mogą w prosty sposób zarządzać powtarzalnymi operacjami, które dotychczas wymagały skryptów systemowych lub ręcznego uruchamiania. Rozszerzenie to pozwala na znaczące usprawnienie pracy i automatyzację rutynowych zadań, co wpływa na efektywność zarządzania danymi i wydajność całego systemu bazodanowego.

pg_cron umożliwia automatyczne uruchamianie cyklicznych zadań PostgreSQL za pomocą SQL. Można go wykorzystać do różnorodnych operacji, zarówno manipulacji danymi, takich jak INSERT, UPDATE, DELETE, jak i procesów administracyjnych, na przykład VACUUM, ANALYZE, REINDEX. Integracja pg_cron z PostgreSQL pozwala na planowanie powtarzalnych zadań bezpośrednio w silniku bazodanowym przy użyciu znanej składni crona systemowego. Rozwiązanie to eliminuje potrzebę tworzenia skryptów do harmonogramowania operacji bazodanowych, ponieważ wszystkie mogą być zarządzane i monitorowane bezpośrednio w bazie danych.

Dodatkowym atutem jest to, że rozszerzenie to nie wymaga interakcji z systemem operacyjnym, co zmniejsza ryzyko nieautoryzowanego dostępu. Możliwość równoczesnego uruchamiania wielu zadań wprowadza elastyczność w zarządzaniu operacjami, jednocześnie dbając o to, aby ta sama instancja zadania nie była uruchamiana więcej niż raz w tym samym czasie. W przypadku, gdy jedno zadanie jest nadal wykonywane, kolejne jego uruchomienie zostanie odłożone w czasie, aż do zakończenia bieżącej operacji.

Instalacja pg_cron

Instalacja pg_cron jest stosunkowo prosta i wymaga jedynie kilku kroków. W przypadku systemów Ubuntu oraz Debian wystarczy zainstalować pakiet postgresql-17-cron za pomocą menedżera pakietów apt-get:

Ubuntu/Debian - apt-get -y install postgresql-17-cron

Natomiast na systemach RHEL oraz CentOS instalacja pg_cron odbywa się przez dnf:

RHEL - dnf install -y pg_cron_17

Po zainstalowaniu pakietu, w pliku konfiguracyjnym ‘postgresql.conf’ należy dodać wpis ‘pg_cron’ do sekcji ‘shared_preload_libraries’, a następnie zrestartować silnik PostgreSQL.

Kolejnym krokiem jest stworzenie rozszerzenia w konkretnej bazie danych za pomocą polecenia:

CREATE EXTENSION pg_cron

Jeżeli rozszerzenie ma działać w bazie innej niż domyślna, konieczne jest dodanie w konfiguracji postgresql.conf wpisu:

cron.database_name = 'XYZ' - XYZ nazwa naszej bazy danych

Pg_cron w standardowej konfiguracji wykonuje zadania poprzez nawiązanie nowej sesji z bazą danych za pomocą biblioteki libpq. Z tego względu musimy zapewnić odpowiednią konfigurację plików ‘pg_hba.conf(local + trust/MD5) oraz ‘.pgpass’. Warto również zadbać o nadanie konkretnych uprawnień dla użytkowników, którzy mają mieć dostęp do planowania i wykonywania zadań, aby zapobiec nieautoryzowanym zmianom w harmonogramie operacji.

Harmonogramowanie zadań w pg_cron

Zadania w pg_cron harmonogramuje się w notacji crontab, co sprawia, że składnia jest intuicyjna dla użytkowników znających klasyczny systemowy cron. Każde zadanie definiuje harmonogram w pięciu polach: minut, godzin, dni miesiąca, miesięcy i dni tygodnia. Dzięki temu użytkownicy mogą precyzyjnie określić moment uruchomienia danego zadania, co jest niezwykle istotne w przypadku operacji wymagających optymalnego zarządzania zasobami systemowymi.


 ┌───────────── min (0 - 59)
 │ ┌────────────── hour (0 - 23)
 │ │ ┌─────────────── day of month (1 - 31) or last day of the month ($)
 │ │ │ ┌──────────────── month (1 - 12)
 │ │ │ │ ┌───────────────── day of week (0 - 6) (0 to 6 are Sunday to
 │ │ │ │ │                  Saturday, or use names; 7 is also Sunday)
 │ │ │ │ │
 │ │ │ │ │
 * * * * *

Na przykład, aby uruchomić zadanie VACUUM ANALYZE codziennie o 00:10, wystarczy użyć polecenia:

SELECT cron.schedule('Daily Vacuum', '10 0 * * *', 'VACUUM ANALYZE;');

Można również zaplanować prostą operację CRUD np. DELETE co godzinę. Dzięki takiemu podejściu użytkownicy mogą w łatwy sposób zautomatyzować procesy zarządzania danymi, eliminując konieczność ręcznego wykonywania powtarzalnych operacji. pg_cron pozwala także na definiowanie bardziej skomplikowanych harmonogramów poprzez wykorzystanie specjalnych znaków i wartości, co daje dużą elastyczność w określaniu częstotliwości uruchamiania zaplanowanych zadań.

Na potrzeby tego artykułu, w celu pokazania wyniku poprawnego i błędnego, za pomocą polecenia ‘SELECT cron.schedule’ w poniższych przykładach dodałem dwa zadania, z których jedno jest błędne (niepoprawna składnia).

SELECT cron.schedule('* * * * *', 'SELECT now');
SELECT cron.schedule('* * * * *', 'SELECT 1');

Monitorowanie zadań

Monitorowanie oraz zarządzanie zadaniami i statusami w pg_cron odbywa się poprzez dwie kluczowe tabele: ‘cron.job’ oraz ‘cron.job_run_details’.

Tabela ‘cron.job’ przechowuje metadane dotyczące wszystkich zaplanowanych zadań. Można w niej znaleźć informacje o harmonogramie, poleceniu SQL, nazwie bazy danych, nazwie użytkownika i statusie aktywności zadania. Większość interakcji z tą tabelą powinna być wykonywana przy użyciu funkcji ‘cron.schedule’ i ‘cron.unschedule’.

postgres=# select * from cron.job;
jobid | schedule  |     command     | nodename  | nodeport | database | username | active |   jobname
-------+-----------+-----------------+-----------+----------+----------+----------+--------+--------------
    4 | * * * * * | SELECT 1        | localhost |     5432 | postgres | postgres | t      |
    5 | * * * * * | SELECT now      | localhost |     5432 | postgres | postgres | t      |
    1 |10 0 * * * | VACUUM ANALYZE; | localhost |     5432 | postgres | postgres | t      | Daily Vacuum

Tabela ‘cron.job_run_details’ zawiera informacje historyczne o uruchomionych zadaniach, ich statusie oraz czasie wykonania. Znajdują się w niej dodatkowe szczegóły, takie jak czas rozpoczęcia i zakończenia zadania oraz ewentualne komunikaty zwrotne, informujące o sukcesie lub błędach wykonania. Dzięki temu administratorzy mogą śledzić historię wykonania operacji i w razie potrzeby zdiagnozować potencjalne problemy. Dostępność tych informacji w postaci tabeli SQL ułatwia integrację z innymi narzędziami do monitorowania i raportowania, co może być przydatne w dużych środowiskach bazodanowych.

postgres=# select * from cron.job_run_details;
jobid | runid | job_pid | database | username |     command     |  status   |           return_message            |          start_time           |           end_time
-------+-------+---------+----------+----------+-----------------+-----------+-------------------------------------+-------------------------------+-------------------------------
    4 |     5 |     103 | postgres | postgres | SELECT 1        | succeeded | 1 row                               | 2025-02-11 12:22:00.171625+00 | 2025-02-11 12:22:00.173512+00
    5 |     6 |     104 | postgres | postgres | SELECT now      | failed    | ERROR:  column "now" does not exist+| 2025-02-11 12:22:00.172279+00 | 2025-02-11 12:22:00.174175+00
      |       |         |          |          |                 |           | LINE 1: SELECT now                 +|                               |
      |       |         |          |          |                 |           |                ^                   +|                               |
      |       |         |          |          |                 |           |                                     |                               |
    1 |     7 |     105 | postgres | postgres | VACUUM ANALYZE; | succeeded | VACUUM                              | 2025-02-11 12:22:00.17289+00  | 2025-02-11 12:22:00.260697+00
    4 |     1 |      93 | postgres | postgres | SELECT 1        | succeeded | 1 row                               | 2025-02-11 12:19:00.673702+00 | 2025-02-11 12:19:00.674492+00
    4 |     2 |      96 | postgres | postgres | SELECT 1        | succeeded | 1 row                               | 2025-02-11 12:20:00.460576+00 | 2025-02-11 12:20:00.461248+00
    4 |     3 |      99 | postgres | postgres | SELECT 1        | succeeded | 1 row                               | 2025-02-11 12:21:00.328818+00 | 2025-02-11 12:21:00.337015+00
    5 |     4 |     100 | postgres | postgres | SELECT now      | failed    | ERROR:  column "now" does not exist+| 2025-02-11 12:21:00.330221+00 | 2025-02-11 12:21:00.338479+00
      |       |         |          |          |                 |           | LINE 1: SELECT now                 +|                               |
      |       |         |          |          |                 |           |                ^                   +|                               |
      |       |         |          |          |                 |           |                                     |                               |

Usuwanie zadań

Jeżeli chcemy usunąć konkretne zadanie, wystarczy wykonać ‘SELECT cron.unschedule(jobid)’, podając odpowiedni identyfikator zadania (jobid).

postgres=# select cron.unschedule(jobid) from cron.job;
unschedule
------------
t
t
t
(3 rows)
postgres=# select * from cron.job;
jobid | schedule | command | nodename | nodeport | database | username | active | jobname
-------+----------+---------+----------+----------+----------+----------+--------+---------

Możliwe jest także tymczasowe wyłączenie zadania bez jego usuwania, co można osiągnąć za pomocą polecenia ‘SELECT cron.alter_job((jobid), active := false)’. Takie podejście pozwala na elastyczne zarządzanie harmonogramem, dostosowując go do zmieniających się potrzeb. W praktyce oznacza to, że zadania można dynamicznie aktywować lub dezaktywować w zależności od aktualnych wymagań operacyjnych.

postgres=# SELECT cron.alter_job(7, active := false);
alter_job
-----------
(1 row)
postgres=# select * from cron.job WHERE JOBID = 7;
jobid | schedule  | command  | nodename  | nodeport | database | username | active | jobname
-------+-----------+----------+-----------+----------+----------+----------+--------+---------
    7 | * * * * * | SELECT 1 | localhost |     5432 | postgres | postgres | f      |

Podsumowanie

Podsumowując, pg_cron to potężne rozszerzenie PostgreSQL, pozwalające na efektywne zarządzanie zadaniami administracyjnymi i operacyjnymi w bazie danych. Dzięki niemu można zautomatyzować procesy, takie jak optymalizacja, archiwizacja czy przetwarzanie danych, bez potrzeby korzystania z zewnętrznych narzędzi harmonogramujących. To doskonałe rozwiązanie zarówno dla administratorów baz danych, którzy muszą dbać o sprawność i wydajność systemu, jak i dla deweloperów, którzy chcą zautomatyzować przetwarzanie danych w swoich aplikacjach. pg_cron ułatwia planowanie zadań, zapewnia ich przejrzystą kontrolę i pozwala na elastyczne zarządzanie harmonogramem w obrębie PostgreSQL, co czyni go niezwykle użytecznym narzędziem w codziennej pracy z bazami danych.

Zobacz również