> ## Documentation Index
> Fetch the complete documentation index at: https://docs.loremstock.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Maintaining a Node.js Application in Production

> Monitor, update, and scale a live Node.js application using PM2 monitoring, Winston logging, Sentry error tracking, scheduled tasks, and PM2 cluster mode.

Deploying an application is not the end of the work. Production maintenance means keeping the application running smoothly, catching errors before users report them, applying security patches, backing up data, and scaling when traffic grows. This page covers the full maintenance lifecycle.

## Why Maintenance Matters

| Risk                  | Consequence                      | Prevention                    |
| --------------------- | -------------------------------- | ----------------------------- |
| Uncaught exceptions   | App crashes silently             | Error tracking (Sentry)       |
| Memory leaks          | App slows, eventually OOM crash  | PM2 memory limit + monitoring |
| Outdated dependencies | Security vulnerabilities         | Regular npm audit + update    |
| Full disk (logs)      | App cannot write logs, may crash | Log rotation                  |
| Database corruption   | Data loss                        | Regular backups               |

## PM2 Monitoring

### Real-Time Dashboard

```bash theme={null}
pm2 monit
```

Shows CPU%, memory, restarts, and log tail for all running processes. Press `h` for help, `q` to quit.

### Useful PM2 Commands

```bash theme={null}
pm2 list                    # Status of all processes
pm2 show myapp              # Detailed info for one app
pm2 logs myapp              # Tail logs (stdout + stderr)
pm2 logs myapp --err        # Only error logs
pm2 logs myapp --lines 50   # Last 50 lines
pm2 restart myapp           # Restart with downtime
pm2 reload myapp            # Zero-downtime reload
pm2 flush                   # Clear all log files
```

## Winston Production Logging

```bash theme={null}
npm install winston
```

```javascript theme={null}
// config/logger.js
const winston = require('winston');
const path = require('path');
const fs = require('fs');

// Ensure logs directory exists
fs.mkdirSync(path.join(__dirname, '../logs'), { recursive: true });

const logger = winston.createLogger({
  level: process.env.LOG_LEVEL || 'info',
  format: winston.format.combine(
    winston.format.timestamp(),
    winston.format.errors({ stack: true }),
    winston.format.json()
  ),
  transports: [
    new winston.transports.File({
      filename: 'logs/error.log',
      level: 'error',
      maxsize: 10485760, // 10MB
      maxFiles: 5
    }),
    new winston.transports.File({
      filename: 'logs/combined.log',
      maxsize: 10485760,
      maxFiles: 7
    })
  ]
});

// Console output in development only
if (process.env.NODE_ENV !== 'production') {
  logger.add(new winston.transports.Console({
    format: winston.format.combine(
      winston.format.colorize(),
      winston.format.simple()
    )
  }));
}

module.exports = logger;
```

## Sentry: Error Tracking

Sentry captures uncaught exceptions and reports them with full context (stack trace, user ID, request data).

```bash theme={null}
npm install @sentry/node
```

```javascript theme={null}
// app.js
const Sentry = require('@sentry/node');

Sentry.init({
  dsn: process.env.SENTRY_DSN,
  environment: process.env.NODE_ENV,
  tracesSampleRate: process.env.NODE_ENV === 'production' ? 0.1 : 1.0
});

// Must be FIRST middleware
app.use(Sentry.Handlers.requestHandler());

// ... routes ...

// Must be BEFORE your error handler
app.use(Sentry.Handlers.errorHandler());

// Your custom error handler
app.use((err, req, res, next) => {
  res.status(500).json({ message: 'Internal Server Error' });
});
```

Sentry provides a dashboard where you can see:

* How many users were affected
* Stack trace of every error
* Request details when the error occurred
* Error frequency over time

## Health Check Endpoint

A health check endpoint is the first thing monitoring tools and load balancers call:

```javascript theme={null}
// routes/health.js
const mongoose = require('mongoose');

app.get('/health', async (req, res) => {
  const uptime = process.uptime();
  const mongoState = mongoose.connection.readyState;

  const status = mongoState === 1 ? 'healthy' : 'degraded';

  res.status(mongoState === 1 ? 200 : 503).json({
    status,
    uptime: Math.floor(uptime),
    timestamp: new Date().toISOString(),
    database: mongoState === 1 ? 'connected' : 'disconnected',
    version: process.env.npm_package_version || '1.0.0'
  });
});
```

```bash theme={null}
# Quick health check from anywhere
curl https://api.yourdomain.com/health
```

## Memory Management and Leak Prevention

Node.js uses a garbage collector but memory leaks are still possible.

### PM2 Memory Limit

```javascript theme={null}
// ecosystem.config.js
{
  max_memory_restart: '500M'  // PM2 restarts app if it exceeds 500MB
}
```

### Common Memory Leak Sources

| Cause                            | Example                                 | Fix                               |
| -------------------------------- | --------------------------------------- | --------------------------------- |
| Event listeners not removed      | Adding listener in loop without cleanup | `removeEventListener` or `once()` |
| Global variables accumulating    | Pushing to array that never clears      | Scope variables appropriately     |
| Closed-over database connections | DB connection in request handler        | Use connection pooling            |
| Unclosed streams                 | File streams not `.destroy()`'d         | Always close streams              |

### Monitor Memory

```bash theme={null}
pm2 monit              # Live view
pm2 show myapp         # Includes memory stats
```

## Updating Node.js and Dependencies

### Update Node.js with NVM

```bash theme={null}
nvm install --lts         # Install latest LTS
nvm use --lts             # Switch to it
nvm alias default --lts   # Set as default

# Test the app still works
npm test
pm2 restart myapp
```

### Keep Dependencies Updated

```bash theme={null}
npm outdated              # Show packages with newer versions
npm update                # Update within semver ranges in package.json
npm audit                 # Scan for vulnerabilities
npm audit fix             # Auto-fix where possible
```

Schedule a monthly maintenance window to review outdated packages and apply updates.

## Database Backups

### MySQL Backup with mysqldump

```bash theme={null}
# Full database backup
mysqldump -u root -p swdbd_app > backup_$(date +%Y%m%d).sql

# Restore from backup
mysql -u root -p swdbd_app < backup_20240615.sql

# Backup with compression
mysqldump -u root -p swdbd_app | gzip > backup_$(date +%Y%m%d).sql.gz

# Restore compressed backup
gunzip < backup_20240615.sql.gz | mysql -u root -p swdbd_app
```

Automate with cron via node-cron (see below) or the system crontab:

```bash theme={null}
# System crontab: daily backup at 2 AM
0 2 * * * mysqldump -u root -pYOURPASS swdbd_app > /var/backups/db/backup_$(date +\%Y\%m\%d).sql
```

## Scheduled Tasks with node-cron

```bash theme={null}
npm install node-cron
```

```javascript theme={null}
const cron = require('node-cron');
const logger = require('./config/logger');

// Cron syntax: minute hour day-of-month month day-of-week
// Example: '0 2 * * *' = 2:00 AM every day

// Daily database backup at 2:00 AM
cron.schedule('0 2 * * *', () => {
  logger.info('Starting scheduled database backup');
  const { exec } = require('child_process');
  const date = new Date().toISOString().split('T')[0];
  const cmd = `mysqldump -u ${process.env.DB_USER} -p${process.env.DB_PASS} ${process.env.DB_NAME} > ./backups/backup_${date}.sql`;
  exec(cmd, (err) => {
    if (err) {
      logger.error('Database backup failed', { error: err.message });
    } else {
      logger.info('Database backup completed', { date });
    }
  });
});

// Clean up expired tokens every hour
cron.schedule('0 * * * *', async () => {
  const deleted = await TokenBlacklist.deleteMany({
    expiresAt: { $lt: new Date() }
  });
  logger.info('Expired tokens cleaned up', { count: deleted.deletedCount });
});
```

### Cron Syntax Reference

| Pattern     | Meaning                       |
| ----------- | ----------------------------- |
| `* * * * *` | Every minute                  |
| `0 * * * *` | Every hour                    |
| `0 2 * * *` | 2 AM every day                |
| `0 2 * * 0` | 2 AM every Sunday             |
| `0 0 1 * *` | Midnight on 1st of each month |

## Scaling

### Vertical Scaling

Upgrade the server (more CPU, RAM). Simple but limited and has downtime.

### Horizontal Scaling

Run multiple instances behind a load balancer.

### PM2 Cluster Mode

PM2's cluster mode runs multiple Node.js processes, one per CPU core, sharing the same port:

```javascript theme={null}
// ecosystem.config.js
module.exports = {
  apps: [{
    name: 'myapp',
    script: 'app.js',
    instances: 'max',      // One per CPU core. Or specify: instances: 4
    exec_mode: 'cluster',  // Required for multiple instances
    // ... other config
  }]
};
```

```bash theme={null}
pm2 start ecosystem.config.js --env production
pm2 list   # Shows 4 processes (on a 4-core server)
```

<Warning>
  Cluster mode requires your app to be stateless. If you store session data in memory, different requests go to different processes and lose the session. Use Redis for shared session/cache storage.
</Warning>

## Key Terms

| Term                   | Definition                                                               |
| ---------------------- | ------------------------------------------------------------------------ |
| **Monitoring**         | Observing application health metrics in real time                        |
| **Memory leak**        | Gradual increase in memory usage because allocated memory is never freed |
| **Sentry**             | Error tracking service that captures and reports exceptions with context |
| **node-cron**          | npm package for running scheduled tasks with cron syntax                 |
| **Cluster mode**       | PM2 mode that runs multiple Node.js processes to utilize all CPU cores   |
| **Health check**       | Endpoint returning current application and dependency status             |
| **Maintenance window** | Scheduled time for updates, backups, and maintenance tasks               |
| **Horizontal scaling** | Adding more server instances to handle more traffic                      |
