UZMAN
Production Checklist & Docker
Production'a deploy öncesi kontrol listesi ve container-ready konfigürasyon.
Karar Rehberi
| Durum | Öneri | Örnek veya gerekçe |
|---|---|---|
| Production'a ilk deploy | Uygun: Tüm checklist'i uğra | Güvenlik + stability |
| API ve worker ayrımı | Uygun: Container role split | Scale bağımsız |
| Zero-downtime deploy | Uygun: Rolling update | K8s maxUnavailable: 0 |
| Tek sunucu PoC | Uygun değil: Overkill | docker-compose gerek yok |
| Development ortamı | Uygun değil: InMemory yeter | Container gereksiz |
Production Checklist
| # | Kontrol | Neden |
|---|---|---|
| 1 | SchemaName ayarla | Uygulama tablolarından izole |
| 2 | DisableGlobalLocks = true | Multi-server uyumluluğu |
| 3 | Dashboard auth filter | Hassas veri koruması |
| 4 | DisplayStorageConnectionString = false | CS sızmasını önle |
| 5 | Retry policy tanımla | Infinite retry önle |
| 6 | Queue isolation (critical/default/low) | Priority management |
| 7 | Health check entegrasyonu | Monitoring altyapısına bağla |
| 8 | Graceful shutdown timeout | In-flight job'ları koru |
| 9 | Worker count tuning | Resource kullanımını optimize et |
| 10 | Log level: Hangfire = Information | Sorun teşhisi için |
| 11 | Job retention ayarla | Storage şişmesini önle |
| 12 | DisableConcurrentExecution (recurring) | Çift çalışmayı engelle |
Job Retention (Storage Temizliği)
// Tamamlanan job'ların ne kadar süre saklanacağını ayarlayın
// Varsayılan: Succeeded = 1 gün, Deleted = 1 gün
// Büyük hacimli sistemlerde storage şişmesini önler
builder.Services.AddHangfire(config => config
.UseSqlServerStorage(connectionString, new SqlServerStorageOptions
{
SchemaName = "hangfire",
JobExpirationCheckInterval = TimeSpan.FromMinutes(30), // Temizleme kontrol aralığı
}));
// Job bazında retention (Hangfire Pro — ücretli)
// Community sürümde bu attribute YOKTUR — derleme hatası alırsınız!
// Community'de sadece global expiration (1 gün) geçerlidir, değiştirilemez.
[JobExpirationTimeout(hours: 72)] // Sadece Hangfire Pro!
public async Task GenerateReportAsync(int reportId) { ... }Not: Default retention (1 gün) çoğu proje için yeterlidir. Ama compliance gerektiren sistemlerde (fintech, healthcare) audit trail için daha uzun tutabilirsiniz. Storage boyutunu haftalık izleyin.
Docker Compose (Production-Ready)
docker-compose.yml
services:
hangfire-api:
build: .
environment:
- ASPNETCORE_ENVIRONMENT=Production
- ConnectionStrings__HangfireConnection=Server=sqlserver;Database=HangfireDb;User=sa;Password=${SQL_SA_PASSWORD};TrustServerCertificate=true
- Hangfire__RunServer=false
ports:
- "8080:8080"
depends_on:
sqlserver:
condition: service_healthy
deploy:
resources:
limits:
memory: 512M
cpus: '1.0'
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 30s
timeout: 5s
retries: 3
hangfire-worker:
build: .
environment:
- ASPNETCORE_ENVIRONMENT=Production
- ConnectionStrings__HangfireConnection=Server=sqlserver;Database=HangfireDb;User=sa;Password=${SQL_SA_PASSWORD};TrustServerCertificate=true
- Hangfire__RunServer=true
- Hangfire__WorkerCount=20
- Hangfire__Queues=critical,default,low
depends_on:
sqlserver:
condition: service_healthy
deploy:
replicas: 2
resources:
limits:
memory: 1G
cpus: '2.0'
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 30s
timeout: 5s
retries: 3
hangfire-dashboard:
build: .
environment:
- ASPNETCORE_ENVIRONMENT=Production
- ConnectionStrings__HangfireConnection=Server=sqlserver;Database=HangfireDb;User=sa;Password=${SQL_SA_PASSWORD};TrustServerCertificate=true
- Hangfire__RunServer=false
- Hangfire__EnableDashboard=true
ports:
- "8081:8080"
depends_on:
sqlserver:
condition: service_healthy
deploy:
resources:
limits:
memory: 256M
cpus: '0.5'
sqlserver:
image: mcr.microsoft.com/mssql/server:2022-latest
environment:
- ACCEPT_EULA=Y
- MSSQL_SA_PASSWORD=${SQL_SA_PASSWORD} # .env dosyasından veya secret manager'dan
volumes:
- sqldata:/var/opt/mssql
ports:
- "1433:1433"
deploy:
resources:
limits:
memory: 2G
cpus: '2.0'
healthcheck:
test: /opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P "${SQL_SA_PASSWORD}" -C -Q "SELECT 1"
interval: 10s
timeout: 5s
retries: 5
volumes:
sqldata:# .env dosyası (git'e EKLEME! .gitignore'a ekle)
SQL_SA_PASSWORD=YourStr0ngPwd!ChangeMeInProdSecret yönetimi: Production'da Docker Secrets, HashiCorp Vault veya cloud provider secret manager kullanın. Environment variable'larda plaintext password SADECE local development için kabul edilebilir.
Conditional Server Registration
// Program.cs — aynı codebase, farklı roller
var runServer = builder.Configuration.GetValue<bool>("Hangfire:RunServer");
var enableDashboard = builder.Configuration.GetValue<bool>("Hangfire:EnableDashboard");
builder.Services.AddHangfire(config => config
.UseSqlServerStorage(builder.Configuration.GetConnectionString("HangfireConnection")));
if (runServer)
{
builder.Services.AddHangfireServer(options =>
{
options.WorkerCount = builder.Configuration.GetValue<int>("Hangfire:WorkerCount", 20);
options.Queues = builder.Configuration.GetSection("Hangfire:Queues")
.Get<string[]>() ?? new[] { "default" };
options.ShutdownTimeout = TimeSpan.FromSeconds(30);
});
}
var app = builder.Build();
if (enableDashboard)
{
app.UseHangfireDashboard("/hangfire", new DashboardOptions
{
Authorization = new[] { new HangfireAuthorizationFilter() },
DisplayStorageConnectionString = false
});
}Graceful Shutdown
// Worker container SIGTERM aldığında:
// 1. Yeni job kabul etmeyi durdurur
// 2. Mevcut job'ların tamamlanmasını bekler (ShutdownTimeout kadar)
// 3. Timeout dolarsa in-flight job'lar "Processing" state'te kalır
// 4. SlidingInvisibilityTimeout sonra başka server tarafından alınır
builder.Services.AddHangfireServer(options =>
{
options.ShutdownTimeout = TimeSpan.FromSeconds(30); // Max bekleme
options.StopTimeout = TimeSpan.FromSeconds(15); // Stop sinyali timeout
});
// Kubernetes: terminationGracePeriodSeconds > ShutdownTimeout olmalı
// terminationGracePeriodSeconds: 45 (ShutdownTimeout + buffer)Rolling Update Strategy
# Kubernetes deployment
spec:
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0 # Hiçbir zaman 0 worker olmasın
template:
spec:
terminationGracePeriodSeconds: 45
containers:
- name: hangfire-worker
lifecycle:
preStop:
exec:
command: ["sleep", "5"] # Load balancer drain süresiÖrnek: Deployment sırasında in-flight job kaybı: Eski pod kill ediliyor ama 2 dakikalık job devam ediyor. Çözüm: ShutdownTimeout=120s + terminationGracePeriodSeconds=135s. Pod, işi bitirene kadar bekler. Bitmezse job "Processing" state'te kalır ve SlidingInvisibilityTimeout sonra başka worker tarafından tekrar alınır (idempotent olmalı!).
Versiyon Güncellik Stratejisi
| Aksiyon | Aralık | Araç |
|---|---|---|
| NuGet patch update kontrolü | Haftalık | Dependabot / Renovate |
| Hangfire changelog takibi | Her minor release | GitHub Releases |
| Breaking change testi | Major öncesi | Staging ortamında full regression |
| CompatibilityLevel yükseltme | Major geçişte bir kez | Tüm node'lar güncellendikten sonra |
NuGet pinleme: Production'da Hangfire.Core ve Hangfire.SqlServer versiyonlarını explicit pinleyin. Floating version (*) kullanmayın — beklenmeyen breaking change riski.