Examples/Basic Ping-Pong Worker

Basic Ping-Pong Worker

A simple example demonstrating the basics of isolated-workers: spawning a worker process, sending messages, and receiving responses. This example shows the fundamental request/response pattern with type-safe message definitions.

Basic Ping-Pong Worker

This example demonstrates the fundamental request/response pattern with isolated-workers.

Overview

The ping-pong example shows:

  • How to define message types using DefineMessages
  • How to spawn a worker process
  • How to send messages and receive responses
  • Proper cleanup and shutdown

Files

Shared Message Definitions

First, define the message types in a shared file that both host and worker import:

messages.ts
/**
 * Shared message definitions for the basic-ping example
 *
 * This file is imported by both the host and worker to ensure
 * type safety and avoid duplication.
 */

import { DefineMessages } from 'isolated-workers';

/**
 * Message types for the ping-pong example
 */
export type Messages = DefineMessages<{
  ping: {
    payload: { message: string };
    result: { message: string };
  };
}>;

Host (Client)

The host imports the message types and uses them with createWorker():

host.ts
/**
 * Basic Ping-Pong Worker - Host (Client) Side
 *
 * This script spawns a worker process and sends a ping message,
 * then receives and prints the pong response.
 */

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

// Get the directory of this file for spawning the worker
const __dirname = dirname(fileURLToPath(import.meta.url));

async function main() {
  console.log('Spawning worker process...');

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

  console.log(`Worker spawned with PID: ${worker.pid}`);

  try {
    // Send a ping message
    console.log('Sending ping message...');
    const result = await worker.send('ping', { message: 'ping' });

    console.log('Received response:', result);
  } catch (err) {
    console.error('Error:', (err as Error).message);
  } finally {
    // Always close the worker
    await worker.close();
    console.log('Worker closed successfully');
  }
}

main();

Worker

The worker imports the same message types and uses Handlers for type-safe handlers:

worker.ts
/**
 * Basic Ping-Pong Worker - Worker (Server) Side
 *
 * This script runs as the worker process and responds to ping messages.
 */

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

// Define handlers for incoming messages with proper typing
const handlers: Handlers<Messages> = {
  ping: ({ message }) => {
    console.log(`Worker received: ${message}`);
    return { message: 'pong' };
  },
};

// Start the worker server
async function main() {
  console.log('Worker starting...');

  const server = await startWorkerServer(handlers);

  console.log('Worker ready and waiting for messages');

  // Keep the process alive until explicitly stopped
  process.on('SIGTERM', async () => {
    console.log('Worker received SIGTERM, shutting down...');
    await server.stop();
    process.exit(0);
  });
}

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

Running the Example

pnpm nx run examples:run-example --example=basic-ping

Key Concepts

  1. Message Definitions: Type-safe messages using DefineMessages
  2. Worker Spawning: Creating a worker with createWorker()
  3. Message Exchange: Sending and receiving with automatic correlation
  4. Cleanup: Graceful shutdown with worker.close()

Running the Example

Run the example

bash
pnpm run:basic-ping