Examples/Worker Lifecycle Management

Worker Lifecycle Management

Demonstrates worker lifecycle management including status checking (isActive, isConnected), state persistence across requests, and graceful shutdown. Shows how workers maintain state between messages and how to handle the worker after it's closed.

Worker Lifecycle Management

Demonstrates worker lifecycle management including status checking (isActive, isConnected), state persistence across requests, and graceful shutdown. Shows how workers maintain state between messages and how to handle the worker after it's closed.

Additional Files

messages.ts
/**
 * Shared message definitions for the worker lifecycle example
 */

import { DefineMessages } from 'isolated-workers';

/**
 * Message types for lifecycle demonstration
 */
export type Messages = DefineMessages<{
  getStatus: {
    payload: Record<string, never>;
    result: { uptime: number; requestCount: number };
  };
  incrementCounter: {
    payload: { amount: number };
    result: { newValue: number };
  };
}>;
host.ts
/**
 * Worker Lifecycle Example - Host (Client) Side
 *
 * This example demonstrates worker lifecycle management:
 * - Checking worker status (isActive, isConnected)
 * - Graceful shutdown
 * - Worker state across multiple requests
 */

import { createWorker, WorkerClient } from 'isolated-workers';
import { dirname, join } from 'path';
import { fileURLToPath } from 'url';
import type { Messages } from './messages.js';

const __dirname = dirname(fileURLToPath(import.meta.url));

function printStatus(worker: WorkerClient) {
  console.log(`  PID: ${worker.pid}`);
  console.log(`  isActive: ${worker.isActive}`);
  console.log(`  isConnected: ${worker.isConnected}`);
}

async function main() {
  console.log('Starting worker lifecycle example...\n');

  const worker = await createWorker<Messages>({
    script: join(__dirname, 'worker.ts'),
    timeout: 10000,
  });

  console.log('--- Worker Created ---');
  printStatus(worker);
  console.log();

  try {
    // Make several requests to show state persistence
    console.log('--- Making Requests ---');

    for (let i = 1; i <= 3; i++) {
      await worker.send('incrementCounter', { amount: i * 10 });
      console.log(`Request ${i}: Incremented counter by ${i * 10}`);
    }

    const status = await worker.send('getStatus', {});
    console.log(`\nWorker status after requests:`);
    console.log(`  Uptime: ${status.uptime}ms`);
    console.log(`  Request count: ${status.requestCount}`);
    console.log();

    // Check status before closing
    console.log('--- Before Close ---');
    printStatus(worker);
    console.log();

    // Graceful shutdown
    console.log('--- Closing Worker ---');
    await worker.close();

    // Check status after closing
    console.log('--- After Close ---');
    printStatus(worker);
    console.log();

    // Attempting to send after close should fail
    console.log('--- Attempting Request After Close ---');
    try {
      await worker.send('getStatus', {});
      console.log('ERROR: Should have thrown!');
    } catch (err) {
      console.log(`Expected error: ${(err as Error).message}`);
    }

    console.log('\nWorker lifecycle demonstration complete!');
  } catch (err) {
    console.error('Unexpected error:', err);
    await worker.close();
  }
}

main().catch((err) => {
  console.error('Fatal error:', err);
  process.exit(1);
});
worker.ts
/**
 * Worker Lifecycle Example - Worker (Server) Side
 *
 * This worker maintains state across requests to demonstrate
 * that the worker process persists between messages.
 */

import { startWorkerServer, Handlers } from 'isolated-workers';
import type { Messages } from './messages.js';

// Worker state - persists across requests
const startTime = Date.now();
let requestCount = 0;
let counter = 0;

const handlers: Handlers<Messages> = {
  getStatus: () => {
    requestCount++;
    return {
      uptime: Date.now() - startTime,
      requestCount,
    };
  },

  incrementCounter: ({ amount }) => {
    requestCount++;
    counter += amount;
    console.log(`Worker: Counter incremented by ${amount}, now ${counter}`);
    return { newValue: counter };
  },
};

async function main() {
  console.log('Worker starting...');
  console.log(`Worker PID: ${process.pid}`);

  const server = await startWorkerServer(handlers);

  console.log('Worker ready and accepting requests');

  process.on('SIGTERM', async () => {
    console.log('Worker received SIGTERM');
    console.log(`Final stats: ${requestCount} requests, counter=${counter}`);
    await server.stop();
    process.exit(0);
  });
}

main().catch((err) => {
  console.error('Worker error:', err);
  process.exit(1);
});

Running the Example

Run the example

bash
pnpm run:worker-lifecycle