Skip to content

Node.js Power & Concurrency ​

StruxJS is explicitly designed to harness the full power of Node.js: its non-blocking I/O event loop, Worker Threads for CPU-bound tasks, and multi-core Cluster Engine.


1. Multi-Core Cluster Engine ​

Node.js runs on a single CPU core by default. To utilize all available cores (e.g. 8 cores or 16 cores on a production server), StruxJS provides a built-in ClusterManager.

The Cluster Manager automatically forks HTTP workers to run concurrently across all CPU threads and manages Graceful Shutdown when the server stops, ensuring no requests are dropped.

Usage ​

Modify your production entry point (usually server.ts or bootstrap.ts):

typescript
import { Application, ClusterManager } from "struxjs";

const app = new Application(__dirname);
await app.bootstrap();

// Run on all CPU cores instead of a single core
if (ClusterManager.isMaster()) {
    ClusterManager.fork();
} else {
    await app.start();
}

2. Worker Threads (ThreadPool) ​

While Node.js excels at I/O (Database, Network), its main Event Loop blocks when executing heavy CPU-bound operations like:

  • Image resizing and manipulation
  • Generating large PDF files
  • Encrypting/hashing large amounts of data
  • Heavy mathematical calculations

To keep the main HTTP server responsive (latency < 5ms) while performing heavy tasks, StruxJS provides a ThreadPool engine based on Node's worker_threads.

Usage ​

1. Create a worker file (e.g., workers/image-processor.ts):

typescript
// workers/image-processor.ts
import { parentPort, workerData } from "worker_threads";
import sharp from "sharp";

async function processImage() {
    const { imagePath, width, height } = workerData;
    const buffer = await sharp(imagePath).resize(width, height).toBuffer();
    parentPort?.postMessage(buffer);
}

processImage();

2. Dispatch the work to the ThreadPool from your controller:

typescript
import { ThreadPool } from "struxjs";

export class ImageController {
    public async resize(request, response) {
        // This offloads the CPU work to a separate Thread.
        // The main Event Loop continues processing other HTTP requests!
        const resultBuffer = await ThreadPool.run("./workers/image-processor.ts", {
            imagePath: request.file("avatar").path,
            width: 500,
            height: 500
        });

        return response.type("image/jpeg").send(resultBuffer);
    }
}

3. Route Caching & ETag ​

To maximize speed and minimize database load, StruxJS provides the RouteCacheMiddleware.

When attached to a route, this middleware:

  1. Automatically computes an ETag hash of the HTTP response.
  2. Caches the response in memory for the specified duration (e.g. 60 seconds).
  3. If the client sends an If-None-Match header matching the ETag, StruxJS returns a fast 304 Not Modified without transmitting the body payload, saving massive amounts of bandwidth.

Usage ​

Attach the routeCache middleware to your routes in routes/web.ts or routes/api.ts:

typescript
import { Route } from "struxjs";

// Cache the response for 60 seconds
Route.get("/leaderboard", "LeaderboardController@index").middleware(["routeCache:60"]);

Released under the MIT License.