n8n ile Cron Görevi: Zamanlanmış İş Akışı Kurulumu
Zamanlanmış görevler her sysadmin’in hayatının ayrılmaz bir parçası. Gecenin üçünde çalışan yedekleme scriptleri, saatlik log rotasyonları, haftalık rapor mailleri… Bunların hepsini terminalde cron expression’larla yönetmek bir süre sonra kaosa dönüşüyor. n8n tam da bu noktada devreye giriyor: cron’un gücünü görsel bir iş akışı tasarımcısıyla birleştirip üstüne monitoring, hata yönetimi ve entegrasyon ekliyor. Bu yazıda n8n’de zamanlanmış iş akışlarını nasıl kuracağınızı, production ortamında nelere dikkat etmeniz gerektiğini ve klasik cron’dan neden daha iyi bir deneyim sunduğunu ele alacağım.
n8n Nedir ve Neden Cron Yerine Kullanmalıyım
Önce temel soruyu yanıtlayalım: zaten işleyen bir cron altyapınız varken neden n8n öğrenmeniz gereksin?
Klasik cron’un en büyük problemi görünürlük eksikliği. Bir cron job başarısız olduğunda genellikle ya bir mail alırsınız (eğer mail ayarlarını doğru yaptıysanız) ya da sabah gelip neden backup almadığını merak edersiniz. n8n’de her çalışma kaydedilir, her hata loglanır, her adımın çıktısını görebilirsiniz. Bunun yanında n8n’nin 400’den fazla native entegrasyonu var; Slack’e bildirim göndermek, veritabanına yazmak, API çağırmak için ayrı scriptler yazmak zorunda kalmıyorsunuz.
Şunu da söyleyeyim: n8n klasik cron’un yerini almak için değil, onu tamamlamak için kullanılıyor. Basit bir dosya silme işlemi için n8n kurmak overkill olur. Ama birden fazla sistemi birbirine bağlayan, başarı/başarısızlık bildirimlerine ihtiyaç duyulan, ekip içinde görünür olması gereken iş akışları için n8n mükemmel bir seçim.
Kurulum: Docker ile n8n Ayağa Kaldırma
Production için Docker Compose kullanacağız. Bare metal kurulum yerine container tercih etmemin sebebi taşınabilirlik ve versiyon yönetimi kolaylığı.
mkdir -p /opt/n8n && cd /opt/n8n
Dizin oluşturduktan sonra docker-compose.yml dosyamızı hazırlayalım:
cat > docker-compose.yml << 'EOF'
version: '3.8'
services:
n8n:
image: docker.n8n.io/n8nio/n8n:latest
container_name: n8n
restart: unless-stopped
ports:
- "5678:5678"
environment:
- N8N_BASIC_AUTH_ACTIVE=true
- N8N_BASIC_AUTH_USER=admin
- N8N_BASIC_AUTH_PASSWORD=guclu_sifreniz_buraya
- N8N_HOST=n8n.sirketiniz.com
- N8N_PORT=5678
- N8N_PROTOCOL=https
- WEBHOOK_URL=https://n8n.sirketiniz.com/
- GENERIC_TIMEZONE=Europe/Istanbul
- TZ=Europe/Istanbul
- DB_TYPE=postgresdb
- DB_POSTGRESDB_HOST=postgres
- DB_POSTGRESDB_PORT=5432
- DB_POSTGRESDB_DATABASE=n8n
- DB_POSTGRESDB_USER=n8n
- DB_POSTGRESDB_PASSWORD=db_sifreniz
volumes:
- n8n_data:/home/node/.n8n
depends_on:
- postgres
postgres:
image: postgres:15
container_name: n8n_postgres
restart: unless-stopped
environment:
- POSTGRES_DB=n8n
- POSTGRES_USER=n8n
- POSTGRES_PASSWORD=db_sifreniz
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
n8n_data:
postgres_data:
EOF
Önemli not: GENERIC_TIMEZONE=Europe/Istanbul ayarı kritik. Bunu atladığınızda cron joblarınız UTC saatiyle çalışır ve “neden saat 03:00’de çalışması gereken iş 06:00’da çalıştı” sorusuyla boğuşursunuz. Türkiye’de sistem yönetiyorsanız bu ayarı mutlaka yapın.
docker-compose up -d
docker-compose logs -f n8n
Logları takip edin, “Editor is now accessible via” satırını gördüğünüzde hazırsınız demektir.
Cron Trigger Node’unu Anlamak
n8n’de zamanlanmış iş akışları için Schedule Trigger node’unu kullanıyoruz (eski versiyonlarda Cron node olarak geçiyordu). Bu node’un iki çalışma modu var.
Interval modu: Her X dakika/saat/günde bir çalıştırır. Basit kullanım senaryoları için ideal.
Cron Expression modu: Klasik cron syntax’ını destekler. Daha granüler kontrol istediğinizde bu modu kullanın.
Cron expression hatırlatması:
0 2 *: Her gece saat 02:000 8 1-5: Haftaiçi her sabah 08:00/15 *: Her 15 dakikada bir0 0 1: Her ayın ilk günü gece yarısı0 9,17 1-5: Haftaiçi 09:00 ve 17:00
n8n’nin güzel tarafı bu expression’ları hata yapmadan yazmanıza yardımcı olan bir arayüz sunması. Ama deneyimli biri olarak şunu söylerim: cron syntax’ını ezberden bilmek hala işe yarar, özellikle bir iş akışını programatik olarak oluşturmanız gerektiğinde.
Senaryo 1: Gece Yarısı Veritabanı Yedekleme İş Akışı
En klasik senaryo ile başlayalım. PostgreSQL veritabanını her gece yedekleyip S3’e yükleyen ve sonucu Slack’e bildiren bir iş akışı kuralım.
n8n arayüzünde yeni bir workflow oluşturduktan sonra ilk node’u ekleyin: Schedule Trigger
Ayarlar:
- Mode: Cron Expression
- Expression:
0 2 *
Sonraki node: Execute Command
Bu node sunucunuzda shell komutu çalıştırır. SSH üzerinden uzak sunucuda da çalıştırabilirsiniz ama şimdilik local örnek verelim:
# n8n Execute Command node'una girecek komut
BACKUP_DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="/tmp/backup_${BACKUP_DATE}.sql.gz"
pg_dump
-h localhost
-U postgres
-d production_db
| gzip > ${BACKUP_FILE}
echo "${BACKUP_FILE}"
Komutun stdout çıktısını bir sonraki node’a aktarabilirsiniz. Bu örnekte backup dosyasının adını output olarak veriyoruz.
Sonraki adım S3 yükleme. n8n’nin native AWS S3 node’u var:
- Node: AWS S3
- Operation: Upload
- Bucket Name: sirket-backuplari
- File Name:
backups/db/{{ $json.stdout.trim() | split('/') | last }}
Son olarak Slack bildirimi:
# Slack mesaj formatı (n8n Slack node'unda Message alanına girer)
:white_check_mark: Veritabanı yedeği başarıyla tamamlandı
*Sunucu:* production-db-01
*Tarih:* {{ DateTime.now().setZone('Europe/Istanbul').toFormat('dd.MM.yyyy HH:mm') }}
*Dosya:* {{ $node["Execute Command"].json.stdout.trim() }}
*Boyut:* {{ $node["Execute Command"].json.stdout.trim() }}
Hata durumu için iş akışına bir Error Trigger ekleyin. Bu sayede herhangi bir adım başarısız olduğunda farklı bir Slack kanalına uyarı gider.
Senaryo 2: Disk Kullanım Monitörü
Sistemlerde disk doluluk uyarısı almak için genellikle Nagios veya Zabbix kullanılır. Ama küçük/orta ölçekli ortamlar için n8n ile 10 dakikada basit bir monitor kurabilirsiniz.
Schedule Trigger: /30 * (her 30 dakikada bir)
Execute Command node’u:
df -h | awk 'NR>1 {gsub(/%/,"",$5); if($5+0 > 80) print $0}' | head -20
Bu komut %80 üzerinde dolu olan disk bölümlerini listeler. Eğer çıktı boşsa alarm yok demektir.
Sonraki node bir IF node’u olacak:
- Condition:
{{ $json.stdout.length }}> 0
True branch: Slack veya mail ile uyarı gönder False branch: Herhangi bir aksiyon alma (veya günlük özet raporu için logla)
# Daha detaylı disk kontrolü
#!/bin/bash
THRESHOLD=80
HOSTNAME=$(hostname)
ALERTS=""
while IFS= read -r line; do
USAGE=$(echo "$line" | awk '{gsub(/%/,"",$5); print $5}')
MOUNT=$(echo "$line" | awk '{print $6}')
if [ -n "$USAGE" ] && [ "$USAGE" -gt "$THRESHOLD" ] 2>/dev/null; then
ALERTS="${ALERTS}n- ${MOUNT}: %${USAGE} dolu"
fi
done < <(df -h | tail -n +2)
if [ -n "$ALERTS" ]; then
echo "ALERT:${HOSTNAME}${ALERTS}"
else
echo "OK"
fi
Bu scripti Execute Command’a koyup çıktıyı IF node’unda kontrol edin. “ALERT:” ile başlıyorsa Slack’e gönder, “OK” ise geç.
Senaryo 3: Haftalık Sistem Sağlık Raporu
Pazartesi sabahları ekibe sistem sağlık özeti göndermek için iyi bir senaryo. Cron expression: 0 9 1
Bu iş akışı daha karmaşık olacak çünkü birden fazla Execute Command node’u çalıştırıp sonuçları bir araya getireceğiz.
Node 1 – Uptime bilgisi:
uptime -p && echo "---LOAD---" && cat /proc/loadavg
Node 2 – Bellek durumu:
free -h | awk '/^Mem:/ {printf "Toplam: %s | Kullanılan: %s | Boş: %sn", $2, $3, $4}'
Node 3 – Son 7 günde en çok kaynak tüketen procesler:
ps aux --sort=-%cpu | head -6 | tail -5 | awk '{printf "%-20s CPU:%-6s MEM:%-6sn", $11, $3, $4}'
Node 4 – Başarısız servisler:
systemctl list-units --state=failed --no-legend 2>/dev/null | awk '{print $1}' | head -10
Bu dört node’u çalıştırdıktan sonra bir Code node’u (JavaScript) ile sonuçları birleştirebilirsiniz:
// n8n Code node - Tüm sonuçları birleştir
const uptime = $node["Uptime"].json.stdout || "Bilgi alınamadı";
const memory = $node["Bellek"].json.stdout || "Bilgi alınamadı";
const topProc = $node["Top Procesler"].json.stdout || "Bilgi alınamadı";
const failedSvc = $node["Başarısız Servisler"].json.stdout || "Yok";
const report = {
title: "Haftalık Sistem Sağlık Raporu",
date: new Date().toLocaleDateString('tr-TR'),
sections: {
uptime: uptime.trim(),
memory: memory.trim(),
topProcesses: topProc.trim(),
failedServices: failedSvc.trim() || "Tüm servisler çalışıyor"
}
};
return [{ json: report }];
Bu veriyi sonraki node’da Slack mesajı olarak formatlayabilir ya da HTML mail olarak gönderebilirsiniz.
Hata Yönetimi ve Retry Mekanizması
Production’da en sık göz ardı edilen konu hata yönetimi. n8n’de her node için retry ayarı yapabilirsiniz.
Workflow ayarlarından Error Workflow belirleyin. Bu, herhangi bir workflow hata verdiğinde otomatik tetiklenen ayrı bir iş akışıdır.
Error workflow’da genellikle şu bilgileri yakalarım:
// Error Trigger node'undan gelen veriyi işleme
const errorData = $json;
const alertMessage = {
workflow: errorData.workflow?.name || "Bilinmeyen workflow",
node: errorData.execution?.error?.node?.name || "Bilinmeyen node",
message: errorData.execution?.error?.message || "Detay yok",
timestamp: new Date().toLocaleString('tr-TR', {timeZone: 'Europe/Istanbul'}),
executionId: errorData.execution?.id
};
return [{ json: alertMessage }];
Retry on Fail özelliği node bazında ayarlanabilir:
- Max Tries: 3 (ağ sorunlarında tekrar dene)
- Wait Between Tries: 60 saniye
Bu özellikle webhook çağrıları ve external API entegrasyonlarında hayat kurtarır.
n8n’de Workflow Versiyonlama ve Yedekleme
Bu konu production ortamlarda genellikle atlanıyor ve “workflow’u yanlışlıkla sildik” krizi ile sonuçlanıyor. n8n workflow’larını JSON olarak export edip Git’te tutun.
# n8n CLI ile tüm workflow'ları export et
docker exec n8n n8n export:workflow --all --output=/home/node/.n8n/workflows_backup.json
# Container dışına kopyala
docker cp n8n:/home/node/.n8n/workflows_backup.json
/opt/backups/n8n_workflows_$(date +%Y%m%d).json
Bunu da bir cron job veya n8n workflow’u ile otomatize edebilirsiniz. Tabii bu “kedi fare kovalıyor” gibi biraz meta oluyor ama işe yarıyor.
Git reposuna push etmek için:
#!/bin/bash
# /opt/scripts/backup_n8n_workflows.sh
BACKUP_DIR="/opt/n8n-backups"
DATE=$(date +%Y%m%d_%H%M)
docker exec n8n n8n export:workflow
--all
--output=/home/node/.n8n/export.json
docker cp n8n:/home/node/.n8n/export.json
"${BACKUP_DIR}/workflows_${DATE}.json"
cd ${BACKUP_DIR}
git add .
git commit -m "Workflow backup: ${DATE}"
git push origin main 2>/dev/null || echo "Git push başarısız, lokal backup mevcut"
Execution Log Yönetimi
n8n her çalışmayı kaydettiği için veritabanı zamanla büyür. Production ortamda bunu yönetmeniz gerekiyor.
# n8n environment variable ile execution retention ayarla
# docker-compose.yml'e ekleyin:
- EXECUTIONS_DATA_SAVE_ON_ERROR=all
- EXECUTIONS_DATA_SAVE_ON_SUCCESS=none
- EXECUTIONS_DATA_SAVE_MANUAL_EXECUTIONS=true
- EXECUTIONS_DATA_PRUNE=true
- EXECUTIONS_DATA_MAX_AGE=168
EXECUTIONS_DATA_MAX_AGE=168 değeri saat cinsinden; 168 saat = 7 gün demek. Başarılı çalışmaları kaydetmek istemiyorsanız EXECUTIONS_DATA_SAVE_ON_SUCCESS=none ile depolama maliyetini ciddi oranda düşürürsünüz. Hatalı çalışmaları ise mutlaka kaydedin.
Klasik Cron ile Birlikte Kullanım
n8n her şeyin yerini tutmaz. Çok sık çalışan (her dakika altı), çok hafif işler için sistem cron’u daha verimli. Benim tercih ettiğim yaklaşım şu:
- Her dakikadan sık: Sistem cron
- Dakikadan seyrek, basit komutlar: n8n (görünürlük için)
- Birden fazla sistemle iletişim kuran işler: Kesinlikle n8n
- Ekibin takip etmesi gereken iş akışları: Kesinlikle n8n
Sistem cron’unu n8n webhook’u tetiklemek için de kullanabilirsiniz. Bazı senaryolarda bu hybrid yaklaşım işe yarar:
# /etc/cron.d/n8n_trigger
# Her 5 dakikada n8n webhook'unu tetikle
*/5 * * * * root curl -s -X POST https://n8n.sirketiniz.com/webhook/sistem-kontrolu > /dev/null 2>&1
Bu sayede tetikleme mekanizması olarak cron, iş akışı yönetimi olarak n8n kullanırsınız.
Performans ve Kaynak Kullanımı
n8n Docker container’ı idle durumda yaklaşık 200-300MB RAM tüketir. Ağır iş akışları çalışırken bu rakam artabilir. Küçük bir VM’de (2GB RAM) rahatça çalışır ama aynı anda çok sayıda workflow tetikleniyorsa worker süreçlerini artırmanız gerekebilir.
# Queue mode için worker başlatma (yoğun ortamlar için)
docker run -d
--name n8n_worker
--env-file /opt/n8n/.env
docker.n8n.io/n8nio/n8n:latest
worker
Queue mode aktif etmek için ayrıca Redis gerekiyor. Günde 10-20 workflow çalıştıran standart ortamlarda buna genellikle ihtiyaç olmaz.
Sonuç
n8n ile zamanlanmış iş akışları kurmak, klasik cron yönetimine kıyasla ciddi avantajlar sunuyor: görsel tasarım, entegre hata yönetimi, execution geçmişi ve ekip görünürlüğü. Özellikle birden fazla sistemi birbirine bağlayan veya hata bildirimlerine ihtiyaç duyulan senaryolarda n8n tartışmasız daha iyi bir seçim.
Başlangıç için tavsiyem şu: Mevcut en kritik iki cron job’ınızı n8n’e taşıyın. Birkaç hafta içinde execution geçmişine bakıp “haa, bu iş Salı günü iki kez başarısız olmuş, neden acaba?” diyebileceksiniz. Bu görünürlük tek başına n8n’i öğrenmeye değer kılıyor.
Sorularınız olursa yorum bölümünde yazın. n8n expression syntax’ı veya belirli entegrasyonlar hakkında daha detaylı yazılar gelecek.
