---
title: "Pg_cron ile PostgreSQL İçinde Zamanlanmış Görevler (Cron Jobs)"
description: "PostgreSQL'de pg_cron eklentisi ile zamanlanmış görevler nasıl kurulur? Supabase'de cron job, materialized view refresh, eski veri temizleme ve cron..."
date: 2026-04-14
category: veri-muhendisligi
tags: ["postgresql", "pg-cron", "supabase", "otomasyon", "zamanlama", "sql"]
url: https://mikroerp.dev/blog/postgresql-pg-cron-zamanlanmis-gorevler/
---

## 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

```sql
-- 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:

```sql
-- 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

```sql
-- 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

```sql
-- 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

```sql
-- 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

```sql
-- 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

```sql
-- 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?

```sql
-- 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ştu
- `running` — Çalışıyor

## Dikkat Edilecekler

1. **Timezone**: pg_cron UTC kullanır. Türkiye saati (UTC+3) hesaplamayı unutmayın.
2. **Uzun süren job'lar**: Bir job tamamlanmadan yenisi başlayabilir. Lock mekanizması kullanın.
3. **Transaction**: Her job tek bir SQL statement çalıştırır. Birden fazla komut için function kullanın.
4. **Error handling**: `cron.job_run_details` tablosunu düzenli kontrol edin.

```sql
-- 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](/blog/postgresql-materialized-view-erp-rapor-hizlandirma/) — View'ları 10x hızlandırma
- [PostgreSQL Trigger Fonksiyonları](/blog/postgresql-trigger-fonksiyonlari-rehberi/) — Event-driven otomasyon
- [PostgreSQL Merkezi Audit Log](/blog/postgresql-merkezi-audit-log-sistemi/) — Log temizleme stratejisi
- [Supabase Edge Functions](/blog/supabase-edge-functions-bildirim-sistemi/) — Cron + bildirim entegrasyonu

---

*Bu rehber [pg_cron GitHub](https://github.com/citusdata/pg_cron) ve [Supabase Cron Docs](https://supabase.com/docs/guides/functions/schedule-functions) dokümantasyonuna dayanarak hazırlanmıştır.*