Faktory Worker for Node.js

4.7.1 · active · verified Sun Apr 19

Faktory-worker is a robust Node.js client and worker library designed to integrate with the Faktory job server, enabling asynchronous background job processing within Node.js applications. It provides both a client for pushing jobs to the Faktory server and a worker for fetching and executing those jobs. The current stable version is 4.7.1, with an active development cadence indicated by recent minor releases introducing features like weighted-random queue fetching (v4.4.0) and CLI improvements (v4.5.0). Its key differentiators include comprehensive handling of Faktory job payloads, support for bulk job pushing, flexible queue configuration (including strictly ordered and weighted random processing), and graceful shutdown mechanisms for workers. The library requires Node.js >=16 and is compatible with Faktory server versions greater than 1.6.1. It also ships with TypeScript types, facilitating its use in modern TypeScript projects.

Common errors

Warnings

Install

Imports

Quickstart

This quickstart demonstrates both the worker setup, registering a job ('ResizeImage'), and how a client pushes that job. It includes a basic `process.argv` check to allow running either the worker or client part independently, mirroring real-world deployment where these are separate processes.

import { connect, register, work, ClientOptions } from 'faktory-worker';

// 1. Define your job processing logic
interface ResizeImagePayload {
  id: number;
  size: string;
}

register('ResizeImage', async (payload: ResizeImagePayload) => {
  console.log(`[Worker] Processing job ResizeImage for image ${payload.id} with size ${payload.size}`);
  // Simulate an asynchronous operation, e.g., image resizing or database update
  await new Promise(resolve => setTimeout(resolve, Math.random() * 1000 + 500));
  console.log(`[Worker] Finished ResizeImage for image ${payload.id}`);
});

// 2. Worker startup (typically run in a long-running background process)
async function startFaktoryWorker() {
  console.log('Starting Faktory worker...');
  try {
    const workerOptions: ClientOptions = {
      queues: ['default', 'images'], // Listen to specified queues
      concurrency: 5,                  // Process up to 5 jobs concurrently
      // Faktory server URL can be set via FAKTORY_URL environment variable
      // or explicitly passed: { host: 'localhost', port: 7419 }
      // factory: { host: 'localhost', port: 7419 },
    };
    await work(workerOptions);
    console.log('Faktory worker started and waiting for jobs...');
  } catch (error) {
    console.error(`Faktory worker failed to start: ${error}`);
    // In Node.js, ensure the process exits on critical errors
    if (typeof process !== 'undefined' && process.exit) {
      process.exit(1);
    }
  }
}

// 3. Client job pushing (typically run from an application server or another process)
async function pushFaktoryJob(payload: ResizeImagePayload) {
  let client;
  try {
    console.log(`[Client] Connecting to Faktory server to push job for image ${payload.id}...`);
    client = await connect(); // Connects to Faktory server

    console.log(`[Client] Pushing job 'ResizeImage' with payload:`, payload);
    await client.job('ResizeImage', payload).push();
    console.log(`[Client] Job 'ResizeImage' for image ${payload.id} pushed successfully.`);

    // Example of pushing a bulk of jobs
    // const job1 = client.job('ResizeImage', { id: 102, size: 'medium' });
    // const job2 = client.job('ResizeImage', { id: 103, size: 'small' });
    // const rejected = await client.pushBulk([job1, job2]);
    // if (Object.keys(rejected).length > 0) {
    //   console.error('[Client] Some bulk jobs were rejected:', rejected);
    // }

  } catch (error) {
    console.error(`[Client] Failed to push job: ${error}`);
  } finally {
    if (client) {
      await client.close(); // Important: reuse client or close after use
      console.log('[Client] Disconnected from Faktory server.');
    }
  }
}

// To run this quickstart:
// 1. Ensure a Faktory server is running (e.g., docker run --rm -p 7419:7419 -p 7420:7420 contribsys/faktory)
// 2. Save this file (e.g., `app.ts`).
// 3. Run the worker in one terminal: `ts-node app.ts worker`
// 4. Run the client to push a job in another terminal: `ts-node app.ts client`

const mode = process.argv[2];

if (mode === 'worker') {
  startFaktoryWorker();
} else if (mode === 'client') {
  pushFaktoryJob({ id: 101, size: 'large' });
} else {
  console.log('Usage: ts-node app.ts [worker|client]');
  console.log('Example: ts-node app.ts worker (to start the job processor)');
  console.log('Example: ts-node app.ts client (to push a job)');
  // For a truly single-file runnable demo, you'd push then immediately start a worker
  // but in practice, these are separate long-running processes.
}

view raw JSON →