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.