Node.js Uygulamasını Production’a Hazırlamak: Logging, Error Handling ve Security

Çalışan bir Node.js API'sini işletilebilir hale getirelim: yapılandırma doğrulama, hata sınırları, güvenli loglama, kaynak limitleri ve kontrollü kapanma.

September 17, 2026•3 min read•

Yerel ortamda çalışan bir API ile production'da güvenilir biçimde işletilen API arasında önemli fark vardır. Production'da istemciler bağlantıyı yarıda keser, dış servisler yavaşlar, trafik artar ve deployment sırasında process'ler kapanır. Kodun mutlu yolunun yanında bu koşulların da tasarlanması gerekir.

Bu yazıda yeni bir framework kurmak yerine mevcut Node.js uygulamasına hangi işletim sözleşmelerini eklemeniz gerektiğine odaklanacağız.

Yapılandırmayı başlangıçta doğrulayın

Eksik bir veritabanı adresinin ilk kullanıcı isteğinde fark edilmesi yerine uygulama başlarken belirlenmesi daha öngörülebilirdir. Environment değişkenlerini okuyun, türlerini doğrulayın ve zorunlu değerler eksikse anlamlı biçimde başarısız olun.

const port = Number(process.env.PORT ?? 3000);

if (!Number.isInteger(port) || port < 1 || port > 65535) {
  throw new Error("PORT must be an integer between 1 and 65535");
}

if (!process.env.DATABASE_URL) {
  throw new Error("DATABASE_URL is required");
}

Hata mesajında eksik alanın adını belirtmek yeterlidir; secret değerinin tamamını yazmayın. Development için sessizce kullanılan varsayılan parola production'a taşınmamalıdır. Environment kaynaklı her değer string olduğu için "false" değerini boolean sanmak gibi hataları da düşünün.

Hataları sınırlarında yakalayın

Beklenen iş hatası ile programlama hatasını ayırın. Geçersiz kullanıcı girdisi, bulunamayan kaynak veya geçici dış servis hatası aynı HTTP yanıtını gerektirmez.

Express 5, promise döndüren route handler'ındaki rejection'ı hata işleyicisine iletebilir; Express 4'te aynı davranışı otomatik varsaymayın. Callback, event emitter veya detached background işlerinin hataları ayrıca yönetilmelidir. Sürüm farkı ve middleware sırası Express error handling rehberinde açıklanır.

Merkezi hata middleware'i, beklenen hataları uygun status code'a çevirirken beklenmeyen hatalarda genel bir kullanıcı mesajı üretmelidir. Response başladıysa ikinci kez JSON yazmaya çalışmayın. İstekten kopuk işlerde hata kaydı ve yeniden deneme politikasını ayrı tanımlayın.

Log: teşhis için yeterli, sızıntı için yetersiz

Yapılandırılmış loglarda service, event, request ID, süre ve deployment kimliği gibi alanlar kullanın. Tüm request nesnesini serialize etmek kolay görünür; Authorization, Cookie veya kişisel veriyi de taşıyabilir.

Örnek kayıt:

{
  "level": "warn",
  "event": "upstream_timeout",
  "service": "task-api",
  "request_id": "example-7",
  "dependency": "catalog",
  "duration_ms": 1500
}

Bu sentetik bir örnektir. Logger redaction kurallarını otomatik testlerle kontrol etmek, “kimse parola loglamaz” varsayımından daha sağlamdır. Container ortamında stdout/stderr üzerinden merkezi toplama kullanılabilir; saklama süresi ve erişim yetkisi de açık olmalıdır.

Log üretilmesi kadar log altyapısı yavaşladığında ne olacağı önemlidir. Sınırsız buffer, uygulamanın bellek tüketimini artırabilir.

Timeout, body limiti ve concurrency

İstek gövdesi sınırı koymak tek başına bütün kaynak tüketimini çözmez. JSON boyutu, dosya yükleme, dış servis bekleme süresi ve aynı anda çalıştırılan pahalı iş sayısı ayrı sınırlardır.

Promise.all içine binlerce dış istek koymak kontrollü paralellik değildir. Küçük bir concurrency bütçesi, bounded queue ve iptal politikası belirleyin. İstemci bağlantısı kapandığında downstream işi durdurabiliyorsanız gereksiz kaynak tüketimini azaltabilirsiniz.

Rate limit anahtarının kaynağını da düşünün. Yanlış proxy güveni yüzünden bütün kullanıcıları aynı IP olarak görmek veya saldırganın gönderdiği IP header'ına inanmak yanlış sonuç üretir.

Güvenlik katmanlarını birlikte kurun

TLS, girdi doğrulama, güvenli cookie seçenekleri ve bağımlılık güncellemeleri temel parçalardır. Parametreli sorgular kullanın, istemciye açık alanları sınırlayın ve her kaynakta yetkilendirme uygulayın.

CORS, tarayıcının hangi origin'e yanıtı açacağını düzenler; API'yi başka istemcilerden koruyan authentication mekanizması değildir. Benzer şekilde bir güvenlik header paketi, iş mantığındaki yetki açığını gidermez. Express production security rehberi bu katmanlar için başlangıç çerçevesi sunar.

Process'i gereksiz root yetkisiyle çalıştırmayın. Uygulamanın yalnızca ihtiyacı olan dosya ve servis erişimlerine sahip olması, olası bir açığın etkisini daraltır.

Kontrollü kapanma

Aşağıdaki parça, daha önce app.listen ile oluşturulmuş bir server nesnesi varsayar. Veritabanı ve kuyruk istemcilerini kapatma adımları kendi uygulamanıza ayrıca eklenmelidir.

let stopping = false;

function shutdown(signal) {
  if (stopping) return;
  stopping = true;

  console.log(JSON.stringify({ event: "shutdown_started", signal }));

  const deadline = setTimeout(() => {
    server.closeAllConnections();
    process.exit(1);
  }, 25_000);
  deadline.unref();

  server.close((error) => {
    clearTimeout(deadline);
    process.exitCode = error ? 1 : 0;
    // Uygulamanın DB, kuyruk ve diğer açık kaynaklarını da kapatın.
  });
}

process.on("SIGTERM", () => shutdown("SIGTERM"));
process.on("SIGINT", () => shutdown("SIGINT"));

Bu HTTP sunucusu örneği WebSocket gibi yükseltilmiş bağlantıları veya tüm bağımlılıkları kapatan eksiksiz bir çözüm değildir. Gerçek shutdown akışında deadline, bütün kaynaklar kapatılana kadar korunmalıdır. Sinyal ve process davranışı Node.js process belgesinde açıklanır.

Readiness ile liveness'ı ayırın

Liveness, process'in yeniden başlatılmasını gerektiren bir durum olup olmadığını; readiness ise instance'ın yeni trafik alıp alamayacağını değerlendirmelidir. Geçici veritabanı yavaşlığında bütün instance'ları sürekli yeniden başlatmak arızayı büyütebilir.

Shutdown başladığında readiness'i başarısız hale getirin, yük dengeleyicinin trafik aktarımını durdurmasına fırsat verin ve mevcut istekleri sınırlı sürede bitirin. Bu süreler platformun stop timeout'u ile uyumlu olmalıdır.

Production hazırlığının ölçüsü kontrol listesi uzunluğu değildir. Yeni sürüm, yüksek yük ve bağımlılık kesintisi altında sistemin ne yapacağını bilmeniz; bu davranışı ölçüp gerektiğinde geri alabilmenizdir.