typescriptintermediate

Process Signals and Environment

Handle process signals, environment variables, exit codes, and unhandled errors in Node.js.

typescript
// Environment variables with validation
function getEnv(key: string, fallback?: string): string {
  const value = process.env[key];
  if (value === undefined) {
    if (fallback !== undefined) return fallback;
    throw new Error(`Missing required env var: ${key}`);
  }
  return value;
}

function getEnvInt(key: string, fallback: number): number {
  const value = process.env[key];
  if (!value) return fallback;
  const parsed = parseInt(value, 10);
  if (isNaN(parsed)) throw new Error(`Env ${key} must be a number: '${value}'`);
  return parsed;
}

function getEnvBool(key: string, fallback: boolean): boolean {
  const value = process.env[key]?.toLowerCase();
  if (!value) return fallback;
  return ['true', '1', 'yes'].includes(value);
}

// Process info
console.log('PID:', process.pid);
console.log('Node:', process.version);
console.log('Platform:', process.platform);
console.log('Arch:', process.arch);
console.log('CWD:', process.cwd());
console.log('Memory:', process.memoryUsage());
console.log('Uptime:', process.uptime(), 'seconds');

// Signal handling
const cleanup = () => {
  console.log('\nCleaning up...');
  // Close DB connections, flush logs, etc.
};

process.on('SIGINT', () => {
  console.log('Received SIGINT (Ctrl+C)');
  cleanup();
  process.exit(0);
});

process.on('SIGTERM', () => {
  console.log('Received SIGTERM');
  cleanup();
  process.exit(0);
});

// Unhandled errors
process.on('uncaughtException', (error: Error) => {
  console.error('Uncaught Exception:', error.message);
  console.error(error.stack);
  process.exit(1); // must exit after uncaughtException
});

process.on('unhandledRejection', (reason: unknown) => {
  console.error('Unhandled Rejection:', reason);
  // In newer Node.js, this will crash the process
});

// Exit handling
process.on('exit', (code: number) => {
  console.log(`Process exiting with code: ${code}`);
  // Only synchronous code here!
});

// beforeExit: last chance for async cleanup (not called on SIGINT)
process.on('beforeExit', async (code: number) => {
  console.log(`beforeExit with code: ${code}`);
});

// CLI args
const args = process.argv.slice(2);
console.log('\nCLI args:', args);

// Exit with code
// process.exit(0);  // success
// process.exit(1);  // error
// process.exitCode = 1; // preferred: lets event loop drain

console.log('\nApp running. Send SIGINT (Ctrl+C) to test signal handling.');

Use Cases

  • Graceful server shutdown
  • Environment configuration
  • Error monitoring and recovery

Tags

Related Snippets

Similar patterns you can reuse in the same workflow.