Pg_cron ile PostgreSQL İçinde Zamanlanmış Görevler (Cron Jobs)
PostgreSQL'de pg_cron eklentisi ile zamanlanmış görevler nasıl kurulur? Supabase'de cron job, materialized view refresh, eski veri temizleme ve cron...
Neden Veritabanı İçinde Cron Job?
Genellikle zamanlanmış görevler application layer’da (Node.js, Python) çalıştırılır. Ama bazı görevler veritabanının sorumluluğundadır:
- Materialized view’ları yenilemek
- Eski log kayıtlarını silmek
- İstatistik tablolarını güncellemek
- Geçici verileri temizlemek
Bu görevler için uygulama sunucusu ayakta olmak zorunda olmamalı. pg_cron bunu çözer.
pg_cron Nedir?
pg_cron bir PostgreSQL eklentisidir (extension). Veritabanı içinde Unix cron syntax’ı ile SQL komutlarını zamanlamanızı sağlar.
Supabase’de varsayılan olarak aktiftir — Dashboard’dan doğrudan kullanabilirsiniz.
Cron Expression Syntax
┌───────────── dakika (0-59)
│ ┌───────────── saat (0-23)
│ │ ┌───────────── ayın günü (1-31)
│ │ │ ┌───────────── ay (1-12)
│ │ │ │ ┌───────────── haftanın günü (0-7, 0 ve 7 = Pazar)
│ │ │ │ │
* * * * *
Sık kullanılan örnekler:
| Expression | Anlamı |
|---|---|
* * * * * | Her dakika |
*/5 * * * * | Her 5 dakikada |
0 * * * * | Her saat başı |
0 3 * * * | Her gece saat 03:00 |
0 0 * * 0 | Her Pazar gece yarısı |
0 9 * * 1-5 | Hafta içi her gün 09:00 |
0 0 1 * * | Her ayın 1’i gece yarısı |
Kurulum ve Kullanım
Self-hosted PostgreSQL
-- Extension'ı etkinleştir
CREATE EXTENSION IF NOT EXISTS pg_cron;
-- Cron job zamanlama
SELECT cron.schedule(
'nightly-cleanup', -- job adı
'0 3 * * *', -- her gece 03:00
'DELETE FROM logs WHERE created_at < NOW() - INTERVAL ''30 days'''
);
Supabase (Dashboard)
SQL Editor’da doğrudan çalıştırın:
-- Extension zaten aktif, doğrudan zamanlayabilirsiniz
SELECT cron.schedule(
'refresh-dashboard-stats',
'*/15 * * * *', -- her 15 dakikada
$$
REFRESH MATERIALIZED VIEW CONCURRENTLY mv_sales_summary;
$$
);
Pratik Örnekler
1. Materialized View Yenileme
-- Her 15 dakikada satış özet view'ını güncelle
SELECT cron.schedule(
'refresh-sales-mv',
'*/15 * * * *',
'REFRESH MATERIALIZED VIEW CONCURRENTLY mv_sales_summary'
);
2. Eski Logları Temizleme
-- Her gece 02:00'de 90 günden eski logları sil
SELECT cron.schedule(
'cleanup-old-logs',
'0 2 * * *',
$$
DELETE FROM audit_log
WHERE created_at < NOW() - INTERVAL '90 days';
$$
);
3. Günlük İstatistik Hesaplama
-- Her gece 01:00'de günlük istatistikleri hesapla
SELECT cron.schedule(
'daily-stats',
'0 1 * * *',
$$
INSERT INTO daily_stats (date, total_orders, total_revenue)
SELECT
CURRENT_DATE - 1,
COUNT(*),
SUM(total_amount)
FROM orders
WHERE created_at::date = CURRENT_DATE - 1
ON CONFLICT (date) DO UPDATE SET
total_orders = EXCLUDED.total_orders,
total_revenue = EXCLUDED.total_revenue;
$$
);
4. Süresi Dolmuş Token Temizleme
-- Her saat başı expired session'ları temizle
SELECT cron.schedule(
'cleanup-expired-sessions',
'0 * * * *',
$$
DELETE FROM user_sessions
WHERE expires_at < NOW();
$$
);
Job Yönetimi
-- Tüm job'ları listele
SELECT * FROM cron.job;
-- Job'ı kaldır (adıyla)
SELECT cron.unschedule('nightly-cleanup');
-- Job'ı kaldır (ID ile)
SELECT cron.unschedule(42);
-- Çalışma geçmişini görüntüle
SELECT * FROM cron.job_run_details
ORDER BY start_time DESC
LIMIT 20;
Monitoring: Job’lar Çalışıyor mu?
-- Son 24 saatteki tüm job çalışmalarını kontrol et
SELECT
j.jobname,
jrd.status,
jrd.start_time,
jrd.end_time,
jrd.return_message
FROM cron.job_run_details jrd
JOIN cron.job j ON j.jobid = jrd.jobid
WHERE jrd.start_time > NOW() - INTERVAL '24 hours'
ORDER BY jrd.start_time DESC;
Status değerleri:
succeeded— Başarılıfailed— Hata oluşturunning— Çalışıyor
Dikkat Edilecekler
- Timezone: pg_cron UTC kullanır. Türkiye saati (UTC+3) hesaplamayı unutmayın.
- Uzun süren job’lar: Bir job tamamlanmadan yenisi başlayabilir. Lock mekanizması kullanın.
- Transaction: Her job tek bir SQL statement çalıştırır. Birden fazla komut için function kullanın.
- Error handling:
cron.job_run_detailstablosunu düzenli kontrol edin.
-- Uzun süren job'lar için function kullanımı
CREATE OR REPLACE FUNCTION maintenance_tasks()
RETURNS void AS $$
BEGIN
-- Adım 1: Eski logları sil
DELETE FROM audit_log WHERE created_at < NOW() - INTERVAL '90 days';
-- Adım 2: View'ı yenile
REFRESH MATERIALIZED VIEW CONCURRENTLY mv_dashboard;
-- Adım 3: Vacuum
-- NOT: VACUUM doğrudan fonksiyon içinde çalışmaz,
-- bunun için ayrı bir cron job gerekir
END;
$$ LANGUAGE plpgsql;
SELECT cron.schedule('nightly-maintenance', '0 3 * * *', 'SELECT maintenance_tasks()');
İlgili Yazılar
- PostgreSQL Materialized View — View’ları 10x hızlandırma
- PostgreSQL Trigger Fonksiyonları — Event-driven otomasyon
- PostgreSQL Merkezi Audit Log — Log temizleme stratejisi
- Supabase Edge Functions — Cron + bildirim entegrasyonu
Bu rehber pg_cron GitHub ve Supabase Cron Docs dokümantasyonuna dayanarak hazırlanmıştır.