Tail‑End VM Log Explosion: How I Fixed the “UnhandledPromiseRejection” Crash on a Budget VPS in 10 Minutes
If you’ve ever watched your VPS CPU spike to 100% while a tiny Node.js script writes endless logs, you know the panic that follows. One night, my cheap $5/month Linode turned into a fiery log‑monster, crashing the whole app with an UnhandledPromiseRejection error. The good news? I tamed the beast in under ten minutes without spending a dime on premium monitoring tools.
Why This Matters
Every developer on a budget VPS faces three common villains:
- Unlimited log growth
- Uncaught promise rejections
- Resource‑starved servers
If left unchecked, these issues not only kill your uptime but also hurt SEO, user trust, and ultimately your bottom line. A single crash can drop conversion rates by up to 30% when users hit a 500 error page.
Step‑by‑Step Tutorial
Below is the exact workflow I used to stop the log explosion and catch the offending promise. Follow each step, copy the snippets, and you’ll have a clean, crash‑resistant Node app running in minutes.
-
Diagnose the Problem
SSH into your VPS and check the last 100 lines of the log file:
tail -n 100 /var/log/node/app.logYou’ll likely see a repeating stack trace ending with
UnhandledPromiseRejectionWarning. -
Add a Global Rejection Handler
Place this at the very top of
index.js(or your entry point). It prevents the process from exiting on unhandled rejections.process.on('unhandledRejection', (reason, promise) => { console.error('🛑 Unhandled Rejection:', reason); // Optional: log to external service // sendToSentry(reason); });Tip: Keep the console.error call; it writes to stdout, which most VPS providers capture into/var/log/syslog. -
Throttle Log Writes
Install
winstonwith a rotating file transport to cap log file size.npm install winston winston-daily-rotate-fileThen create
logger.js:const { createLogger, format, transports } = require('winston'); const DailyRotateFile = require('winston-daily-rotate-file'); const logger = createLogger({ level: 'info', format: format.combine( format.timestamp(), format.printf(info => `${info.timestamp} ${info.level}: ${info.message}`) ), transports: [ new DailyRotateFile({ filename: 'logs/app-%DATE%.log', datePattern: 'YYYY-MM-DD', maxSize: '5m', maxFiles: '14d', zippedArchive: true }) ] }); module.exports = logger;Replace any
console.logcalls withlogger.info()orlogger.error(). -
Patch the Faulty Promise
Identify the offending async function. In my case it was a call to a third‑party API that occasionally timed out.
async function fetchData(url) { try { const res = await fetch(url, { timeout: 5000 }); if (!res.ok) throw new Error('Bad response'); return await res.json(); } catch (err) { logger.error(`Fetch error: ${err.message}`); // Graceful fallback return { fallback: true }; } }Warning: Never swallow errors without logging. The logger above ensures you still see why the fallback ran. -
Restart & Verify
Pull the changes, rebuild, and restart the service (systemd example):
git pull origin main npm ci sudo systemctl restart mynode.service sudo systemctl status mynode.serviceWatch the logs for the next 5 minutes to confirm no more “UnhandledPromiseRejection” messages appear.
Real‑World Use Case
After the fix, my e‑commerce microservice handled 2,000 requests per minute without a single crash. The rotating logs kept disk usage under 150 MB on a 2 GB VPS, and the global rejection handler caught three silent API timeouts that would have otherwise taken my site offline.
Results / Outcome
- CPU usage dropped from 97% to 12% during idle periods.
- Disk consumption stabilized at 120 MB for a full month of logs.
- Zero “500 Internal Server Error” incidents in the following two weeks.
- SEO bounce‑rate improved by 5% after uptime restored.
Bonus Tips
- Use a health‑check endpoint. A simple
/pingroute returns 200 OK; configure your VPS provider to ping it every minute. - Set “max_old_space_size”. For Node 14+, launch with
node --max_old_space_size=256 index.jsto cap memory usage. - Send critical errors to Discord/Slack. A quick webhook can alert you before users notice.
- Consider a free APM. Tools like Sentry have generous free tiers for low‑traffic apps.
Monetization Sidebar (Optional)
If you run a tutorial site, sprinkle affiliate links to VPS providers or monitoring services. A simple “Upgrade to a $10/month VPS for 2 GB RAM” call‑to‑action can generate recurring revenue while truly helping readers.
Fixing a log explosion and an UnhandledPromiseRejection doesn’t have to be a multi‑hour nightmare. With a few lines of code, a rotating logger, and a global rejection handler, even the cheapest VPS can run smoothly. Deploy the steps above, watch your metrics improve, and get back to building the features that actually grow your business.
No comments:
Post a Comment