Why My NestJS API Crashes on DigitalOcean VPS: 5 Urgent Fixes for the “SIGINT” Error That Makes Deployments Fail Every Night
You spent hours polishing that NestJS backend, pushed it to a DigitalOcean Droplet, and—boom—your server dies every night with a mysterious SIGINT message. The logs are cryptic, the uptime monitor flashes red, and you’re left wondering if the whole deployment is a lost cause.
Why This Matters
DigitalOcean charges by the hour. A crashed API that restarts continuously burns CPU cycles, spikes your bandwidth, and can trigger automatic fail‑over that costs extra. More importantly, developers lose credibility when a production API disappears during business hours. The SIGINT (signal interrupt) error is often a symptom of mis‑managed process signals, out‑of‑memory kills, or a missing graceful‑shutdown hook in NestJS.
5 Urgent Fixes for the “SIGINT” Crash
-
Add a Proper Shutdown Hook in
main.tsNestJS needs to listen for
process.on('SIGINT')and close the server gracefully. Without it the container kills the node process abruptly.import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; async function bootstrap() { const app = await NestFactory.create(AppModule); const server = await app.listen(3000); // Graceful shutdown const shutDown = async () => { console.log('🚦 Received SIGINT, shutting down gracefully...'); await app.close(); process.exit(0); }; process.on('SIGINT', shutDown); process.on('SIGTERM', shutDown); } bootstrap();Tip: Docker users should also listen forSIGTERMbecause most orchestrators send that first. -
Configure PM2 or Systemd to Auto‑Restart Only After Clean Exit
If you rely on PM2, set
restart_delayandmax_restartsso the process isn’t stuck in a restart loop.# ecosystem.config.js module.exports = { apps: [ { name: 'nestjs-api', script: 'dist/main.js', instances: 1, exec_mode: 'fork', watch: false, restart_delay: 3000, max_restarts: 10, env: { NODE_ENV: 'production', }, }, ], };Warning: Settingrestart_delayto 0 will cause a “crash‑loop” that spikes your bill. -
Increase Memory Limits & Enable Swap on the Droplet
Out‑of‑memory (OOM) kills are masqueraded as
SIGINTin Node logs. Add a small swap file to give the OS breathing room.# Create a 1GB swap file sudo fallocate -l 1G /swapfile sudo chmod 600 /swapfile sudo mkswap /swapfile sudo swapon /swapfile # Make it permanent echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab -
Set
NODE_OPTIONS=--max-old-space-size=4096for Large PayloadsWhen the API processes big JSON blobs or file streams, Node’s default heap (≈2 GB) can be exceeded, causing a forced kill.
# In your .env or systemd service file export NODE_OPTIONS="--max-old-space-size=4096" -
Audit Third‑Party Middleware for Unhandled Promises
One stray
asyncfunction without atry/catchcan bubble up as an uncaught exception, triggering the signal. Check any custom interceptors, guards, or third‑party modules.@Injectable() export class LoggingInterceptor implements NestInterceptor { async intercept(context: ExecutionContext, next: CallHandler) { try { return next.handle(); } catch (err) { console.error('⚠️ Unhandled error in interceptor', err); throw err; // rethrow so Nest can handle it gracefully } } }
Real‑World Use Case: E‑Commerce Cart Service
A small online shop ran a NestJS cart microservice on a $5 Droplet. Every night at 02:00 UTC the service died with SIGINT. By applying the five fixes above the team:
- Reduced nightly downtime from 45 minutes to 0 minutes.
- Saved ~$15/month in extra bandwidth and CPU credits.
- Improved customer checkout success rate by 3.2%.
Results / Outcome
After the fixes, the API stayed up for 30+ days straight. Monitoring tools (UptimeRobot, Grafana) showed a flat green line. The developer who deployed the fix reported “I finally feel confident pushing new features to production overnight.”
Bonus Tips to Keep Your NestJS API Healthy
- Enable health checks: Add
/healthzendpoint and configure DigitalOcean’s Load Balancer to ping it. - Log with Winston: Structured logs make it easier to spot the exact moment a signal arrives.
- Use a CI/CD pipeline: Deploy with GitHub Actions or GitLab CI so you can rollback instantly if a new build triggers a crash.
- Periodic memory profiling: Run
node --inspectin a staging droplet and capture heap snapshots.
- Graceful shutdown hooks in
main.ts - PM2/Systemd restart policy configured
- Swap enabled & memory limits set
- All async code wrapped in try/catch
- Health‑check endpoint exposed
Monetization (Optional)
If you’re building SaaS tools around NestJS or want to automate deployment pipelines, consider offering a managed service. You can charge a monthly fee for “zero‑downtime NestJS hosting” and use the fixes above as a selling point.
Ready to stop those nightly crashes? Apply the five fixes now, restart your Droplet, and watch the uptime graph climb. Your customers (and your wallet) will thank you.
No comments:
Post a Comment