# How WorkerService Handles Background Initialization Without Blocking HTTP Requests in Claude-Mem

> Learn how Claude-Mems WorkerService initializes in the background without blocking HTTP requests. Discover its elegant solution for deferred startup.

- Repository: [Alex Newman/claude-mem](https://github.com/thedotmack/claude-mem)
- Tags: internals
- Published: 2026-02-16

---

**Claude-Mem’s `WorkerService` starts its HTTP server immediately and defers all heavyweight initialization to a background promise, using a guard middleware to queue or reject API requests until startup completes.**

The `WorkerService` in Claude-Mem acts as the core orchestrator responsible for bootstrapping the database, Chroma vector store, and MCP connections. To ensure the service remains responsive to health checks and orchestration probes, it must prevent these lengthy startup tasks from blocking the HTTP request pipeline. The implementation achieves this through a carefully sequenced startup flow and a promise-based synchronization mechanism defined in [`src/services/worker-service.ts`](https://github.com/thedotmack/claude-mem/blob/main/src/services/worker-service.ts).

## The Initialization Challenge in Claude-Mem

When Claude-Mem starts, it must perform several I/O-intensive operations before it can serve meaningful API traffic: loading the database manager, selecting the operational mode, starting the Chroma server, and establishing MCP connections. If these steps executed synchronously before the HTTP server bound to its port, orchestrators like Kubernetes would see the container as "not ready" and potentially trigger unnecessary restarts. The `WorkerService` solves this by separating "server availability" from "service readiness."

## How WorkerService Implements Non-Blocking Startup

The non-blocking behavior relies on three coordinated mechanisms: a deferred promise for tracking initialization state, immediate server binding, and asynchronous background tasks.

### Promise-Based Initialization Tracking

Inside the `WorkerService` constructor, the service creates a `Promise<void>` that acts as a gate for incoming requests. The constructor stores both the promise and its resolver function, allowing the background process to signal completion later.

```typescript
// Inside src/services/worker-service.ts
private initializationComplete: Promise<void>;
private resolveInitialization!: () => void;
private initializationCompleteFlag: boolean = false;

constructor() {
  // Create the promise that will resolve when init finishes
  this.initializationComplete = new Promise<void>((resolve) => {
    this.resolveInitialization = resolve;
  });
}

```

The `initializationCompleteFlag` boolean provides a fast synchronous check, while the promise supports asynchronous waiting with timeout capabilities.

### Immediate Server Startup

The `start()` method in `WorkerService` binds the HTTP server to its configured port and host before any heavy initialization begins. This ensures the operating system marks the port as occupied and orchestrators receive successful TCP health checks immediately.

```typescript
async start(): Promise<void> {
  const port = getWorkerPort();
  const host = getWorkerHost();

  // 1. HTTP server starts first
  await this.server.listen(port, host);

  // 2. PID file written after listen succeeds
  writePidFile({ 
    pid: process.pid, 
    port, 
    startedAt: new Date().toISOString() 
  });

  logger.info('SYSTEM', 'Worker started', { host, port, pid: process.pid });

  // 3. Heavy init runs in background without blocking
  this.initializeBackground().catch(err => {
    logger.error('SYSTEM', 'Background initialization failed', {}, err);
  });
}

```

By not `await`-ing the `initializeBackground()` call, the `start()` method returns control to the caller immediately, leaving the background tasks to run concurrently.

### Background Initialization Workflow

The `initializeBackground()` method performs the actual heavyweight setup: loading the mode configuration, starting the Chroma server, initializing the database manager, and establishing MCP connections. Only after all these steps complete does it resolve the initialization promise.

```typescript
private async initializeBackground(): Promise<void> {
  // ... load mode, start Chroma, init DB, connect MCP ...
  await this.dbManager.initialize();

  // Mark init as done and release waiting requests
  this.initializationCompleteFlag = true;
  this.resolveInitialization();  // Resolves the promise used by guard middleware
  
  logger.info('SYSTEM', 'Background initialization complete');
}

```

## Protecting API Routes During Initialization

With the server accepting connections immediately but the service not yet ready, `WorkerService` must prevent premature API requests from executing. It accomplishes this through a guard middleware that pauses or rejects requests based on the initialization state.

### The Guard Middleware Implementation

In `registerRoutes()`, the service installs an Express middleware for all `/api/*` routes (with specific exemptions for health checks). This middleware checks the `initializationCompleteFlag` synchronously for fast-path continuation, or awaits the initialization promise if the flag is false.

```typescript
// Inside registerRoutes() in src/services/worker-service.ts
this.server.app.use('/api', async (req, res, next) => {
  // Fast path: init already complete
  if (this.initializationCompleteFlag) {
    return next();
  }

  const timeoutMs = 30_000;
  const timeout = new Promise<never>((_, reject) =>
    setTimeout(() => reject(new Error('Database initialization timeout')), timeoutMs)
  );

  try {
    // Wait for background init or timeout
    await Promise.race([this.initializationComplete, timeout]);
    next();  // Proceed to actual handler
  } catch {
    logger.error('HTTP', `Request to ${req.method} ${req.path} rejected — DB not initialized`);
    res.status(503).json({
      error: 'Service initializing',
      message: 'Database is still initializing, please retry'
    });
  }
});

```

### Handling Timeouts and 503 Responses

If the background initialization takes longer than 30 seconds, the middleware rejects the request with HTTP **503 Service Unavailable**. This signals to clients and load balancers that the service is temporarily unavailable but actively recovering, distinguishing it from a hard failure. Clients receive a JSON payload explaining the initialization state.

### Readiness Endpoint Integration

The [`src/services/server/Server.ts`](https://github.com/thedotmack/claude-mem/blob/main/src/services/server/Server.ts) file exposes a `/api/readiness` endpoint that mirrors the initialization flag logic. While the guard middleware protects individual routes, the readiness probe provides a lightweight check for orchestrators.

```typescript
// Conceptual implementation in Server.ts
app.get('/api/readiness', (req, res) => {
  if (workerService.isInitializationComplete()) {
    res.status(200).json({ status: 'ready' });
  } else {
    res.status(503).json({ status: 'initializing' });
  }
});

```

This dual mechanism—middleware for request protection and explicit endpoint for health checks—ensures robust handling of the initialization window.

## Summary

- **Immediate server binding**: `WorkerService.start()` binds the HTTP server before any heavy initialization, ensuring the port is active for health probes.
- **Promise-based synchronization**: A deferred `Promise<void>` and boolean flag track initialization state, allowing asynchronous coordination between the main thread and background workers.
- **Non-blocking background tasks**: `initializeBackground()` runs database, Chroma, and MCP setup without blocking the `start()` method return.
- **Guard middleware protection**: All `/api/*` routes (except health checks) pass through middleware that waits for initialization or returns **503 Service Unavailable** after a 30-second timeout.
- **Readiness endpoint**: `/api/readiness` in [`src/services/server/Server.ts`](https://github.com/thedotmack/claude-mem/blob/main/src/services/server/Server.ts) provides explicit health state for orchestrators, reflecting the same initialization flag used by the middleware.

## Frequently Asked Questions

### How does WorkerService prevent database initialization from blocking incoming HTTP requests?

`WorkerService` separates the HTTP server startup from the database initialization sequence. In [`src/services/worker-service.ts`](https://github.com/thedotmack/claude-mem/blob/main/src/services/worker-service.ts), the `start()` method calls `await this.server.listen()` to bind the port immediately, then invokes `this.initializeBackground()` without awaiting it. This allows the server to accept connections while the database, Chroma server, and MCP connections initialize in the background. A guard middleware then holds API requests until the initialization promise resolves.

### What happens to API requests received before WorkerService finishes initializing?

Requests to `/api/*` routes hit a guard middleware that checks `this.initializationCompleteFlag`. If initialization is incomplete, the middleware races the `initializationComplete` promise against a 30-second timeout. If the background work finishes first, the request proceeds normally. If the timeout fires first, the client receives an HTTP **503 Service Unavailable** response with a JSON error message indicating the service is still initializing.

### How does the readiness endpoint differ from the guard middleware?

The readiness endpoint at `/api/readiness` (defined in [`src/services/server/Server.ts`](https://github.com/thedotmack/claude-mem/blob/main/src/services/server/Server.ts)) provides an explicit health check for orchestrators like Kubernetes, returning **200 OK** when `initializationCompleteFlag` is true and **503** when false. The guard middleware performs the same flag check but operates transparently on functional API routes, automatically queueing or rejecting requests without requiring clients to manually poll a health endpoint first.

### Why does WorkerService use both a boolean flag and a promise for initialization tracking?

The boolean `initializationCompleteFlag` provides a fast synchronous check used by the guard middleware to immediately pass through requests when initialization is already complete, avoiding unnecessary promise overhead. The `initializationComplete` promise enables asynchronous waiting for the rare cases where requests arrive during the initialization window, allowing the middleware to suspend the request until the background work signals completion via `resolveInitialization()`.