Zero-Downtime-Deployment von TypeScript-Diensten: Schritt-für-Schritt-Anleitung

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Wie aktualisiert man einen Dienst, ohne die Benutzer zu stören?



Stellen Sie sich vor: Freitagabend, Sie möchten schnell einen Bugfix in die Produktion einspielen. Sie drücken auf Deploy – und Ihr Messenger, Online-Kino oder CRM fällt für 30 Sekunden aus. Tausende Benutzer sehen in diesem Moment einen 502 Bad Gateway. Und wenn es sich um ein Zahlungsgateway handelt? Rechnen Sie mit Verlusten.



Zero-Downtime-Deployment (Bereitstellung ohne Ausfallzeiten) ist kein Luxus, sondern ein Standard für moderne TypeScript-Dienste. In diesem Artikel behandeln wir echte Techniken, die in der Produktion verwendet werden: von Graceful Shutdown bis hin zu Blue-Green-Deployment und Rolling Update. Sie erhalten einsatzbereite Patterns in TypeScript.



Warum ist ein normales Deployment einer TypeScript-Anwendung gefährlich?



Wenn Sie npm run build && node dist/index.js ausführen, treten mehrere Probleme auf:



  • Verbindungsabbrüche – der alte Prozess wird beendet, während noch neue Anfragen eingehen.
  • Datenverlust im Arbeitsspeicher – nicht gespeicherte Sitzungen, Cache, Warteschlangen.
  • Schmutziger Start – der neue Prozess konnte sich nicht aufwärmen, erhält aber bereits Traffic.


In TypeScript (Node.js) wird dies durch Asynchronität verschärft: Sie wissen nicht, welche Promises noch ausgeführt werden. Aber es gibt eine Lösung.



Technik #1: Graceful Shutdown (höfliches Beenden)



Die Basis von Zero-Downtime ist die korrekte Behandlung von Betriebssystem-Signalen. Wenn der Orchestrator (Kubernetes, PM2) beschließt, Ihren Dienst zu stoppen, sendet er SIGTERM. Ihr Code sollte keine neuen Anfragen mehr annehmen, auf die Fertigstellung der aktuellen warten und erst dann beenden.



Implementierung in TypeScript mit Express



import express, { Request, Response } from 'express';import http from 'http';

const app = express();let server: http.Server;

app.get('/health', (req: Request, res: Response) => { res.status(200).json({ status: 'ok' });});

// Signal von Docker/K8sprocess.on('SIGTERM', async () => { console.log('SIGTERM erhalten, beginne mit Graceful Shutdown...'); // 1. Keine neuen Verbindungen mehr annehmen server.close(() => { console.log('HTTP-Server geschlossen'); // 2. Verbindungen zu DB, Redis usw. schließen // await db.disconnect(); process.exit(0); });

// 3. Zeit für aktuelle Anfragen geben (Timeout 30 Sek.) setTimeout(() => { console.error('Erzwungene Beendigung durch Timeout'); process.exit(1); }, 30000);});

const PORT = process.env.PORT || 3000;server = app.listen(PORT, () => { console.log(`Dienst gestartet auf Port ${PORT}`);});


Wichtig: Verwenden Sie in TypeScript http.Server aus dem Modul http, nicht den Express-Typ. Die Methode server.close() behandelt Keep-Alive-Verbindungen korrekt.



Technik #2: Rolling Update (schrittweise Aktualisierung)



Wenn Sie mehrere Replikate Ihres Dienstes haben (3-5 Instanzen laufen), aktualisiert ein Rolling Update diese nacheinander. Während einer neu startet, nehmen die anderen den Traffic entgegen.



Beispiel für ein Kubernetes Deployment



# deployment.yamlapiVersion: apps/v1kind: Deploymentmetadata:  name: my-typescript-servicespec:  replicas: 3  strategy:    type: RollingUpdate    rollingUpdate:      maxUnavailable: 1      # wie viele Pods nicht verfügbar sein dürfen      maxSurge: 1            # wie viele neue Pods über dem Plan erstellt werden dürfen  template:    spec:      containers:      - name: app        image: myregistry/service:v2        ports:        - containerPort: 3000        livenessProbe:          httpGet:            path: /health            port: 3000          initialDelaySeconds: 5          periodSeconds: 10        readinessProbe:          httpGet:            path: /ready            port: 3000          initialDelaySeconds: 3          periodSeconds: 5


Fügen Sie Ihrer TypeScript-Anwendung einen Endpunkt /ready hinzu, der nur dann 200 zurückgibt, wenn der Dienst

Blogs

Buchempfehlungen