- MessageType: 'CALL' | 'RESPONSE' | 'REGISTER' | 'HEARTBEAT'
- ResponseStatus: 'success' | 'error'
- MethodHandler: Function type for handlers
- MethodRegistry: Map of method handlers
- IPCContext: Request chain tracking
- BaseMessage: Common message fields
- CallMessage: Method call request
- ResponseMessage: Method call result
- RegisterMessage: Service registration
- HeartbeatMessage: Keep-alive
- IPCMessage: Union of all messages
- PendingRequest: Promise tracking
- ServiceEntry: Connected service info
- IPCServerConfig: Gateway configuration
- IPCClientConfig: Service configuration
- IPCError: Custom error class
- IPCErrorCode: Error code enum
- Message serialization/deserialization (length-prefixed JSON)
- ID generation
- Context management (create, extend, validate)
- Time/deadline helpers
serialize()- Converts message to length-prefixed bufferdeserialize()- Converts buffer back to messagereadMessageLength()- Peek at message length without parsinghasCompleteMessage()- Check if buffer has full messagesplitMessages()- Handle multiple messages in one buffer
generateId()- Unique request IDsgenerateRootId()- Correlation IDs for tracking
createContext()- Start new request chainextendContext()- Propagate context to nested callsvalidateContext()- Ensure context is valid
isDeadlineExceeded()- Check timeoutsgetRemainingTime()- Calculate time leftcalculateDeadline()- Convert duration to timestamp
createCallMessage()- Build CALL messagescreateSuccessResponse()- Build success responsescreateErrorResponse()- Build error responses
validateMessage()- Ensure message structureisMaxDepthExceeded()- Prevent infinite loops
formatMessageForLog()- Pretty print messagesformatContext()- Display call chain
calculateBackoff()- Exponential backoff for retriessleep()- Async delaycreateTimeoutPromise()- Timeout helper
Buffer: [0x00, 0x00, 0x00, 0x32] + JSON bytes
└─────────┬────────┘
50 bytes (length)Order creates context:
{ root: 'root-123', chain: ['order'], depth: 1 }
Order calls User (extends context):
{ root: 'root-123', chain: ['order', 'user'], depth: 2 }
User calls Role (extends again):
{ root: 'root-123', chain: ['order', 'user', 'role'], depth: 3 }The IPC Server acts as a hub that:
- Listens on a Unix Domain Socket
- Accepts connections from services
- Routes CALL messages to target services
- Routes RESPONSE messages back to callers
- Manages service registry
- Monitors service health via heartbeats
Gateway (IPC Server)
/tmp/bro-gateway.sock
|
+----------------+----------------+
| | |
Order Service Cart Service User Service
(connects) (connects) (connects)
1. Service A connects → Gateway stores connection
2. Service B connects → Gateway stores connection
3. Service A sends CALL to Service B
↓
4. Gateway receives CALL
↓
5. Gateway looks up Service B socket
↓
6. Gateway forwards CALL to Service B
↓
7. Service B executes method
↓
8. Service B sends RESPONSE to Gateway
↓
9. Gateway forwards RESPONSE to Service A
↓
10. Service A receives result
import { IPCServer } from "./ipc/core/ipc-server";
// Create server
const server = new IPCServer({
socketPath: "/tmp/bro-gateway.sock",
debug: true,
});
// Listen to events
server.on("service-registered", (data) => {
console.log(`Service registered: ${data.serviceName}`);
});
server.on("call-routed", (data) => {
console.log(`Routing: ${data.from} → ${data.to}.${data.method}()`);
});
// Start server
await server.start();
console.log("Gateway running!");
// Later... stop server
await server.stop();new IPCServer(config?: Partial)Creates a new IPC Server instance.
Parameters:
config(optional): Server configuration object
Example:
const server = new IPCServer({
socketPath: "/tmp/bro-gateway.sock",
heartbeatInterval: 30000,
timeout: 30000,
debug: false,
});Starts the IPC Server and begins listening for connections.
Returns: Promise that resolves when server is listening
Throws: IPCError if server fails to start
Example:
await server.start();
console.log("Server started successfully!");What it does:
- Removes existing socket file if present
- Creates net.Server
- Listens on Unix socket path
- Sets up connection handlers
- Emits
startedevent
Stops the IPC Server gracefully.
Returns: Promise that resolves when server is stopped
Example:
await server.stop();
console.log("Server stopped");What it does:
- Closes all service connections
- Closes server
- Removes socket file
- Clears registries
- Emits
stoppedevent
Gets list of connected service names.
Returns: Array of service names
Example:
const services = server.getConnectedServices();
console.log("Connected services:", services);
// Output: ['order-service', 'user-service', 'cart-service']Gets detailed information about a specific service.
Parameters:
serviceName: Name of the service
Returns: ServiceEntry object or undefined if not found
Example:
const service = server.getService("order-service");
console.log(service);
// Output:
// {
// name: 'order-service',
// socket: Socket {...},
// methods: ['getOrderList', 'createOrder'],
// connectedAt: 1699005123456,
// lastHeartbeat: 1699005150000,
// metadata: {}
// }Checks if a service is currently connected.
Parameters:
serviceName: Name of the service
Returns: true if connected, false otherwise
Example:
if (server.isServiceConnected("user-service")) {
console.log("User service is online");
} else {
console.log("User service is offline");
}Gets server status and statistics.
Returns: Status object with server information
Example:
const status = server.getStatus();
console.log(status);
// Output:
// {
// running: true,
// socketPath: '/tmp/bro-gateway.sock',
// connectedServices: 3,
// services: ['order-service', 'user-service', 'cart-service']
// }interface IPCServerConfig {
socketPath: string; // Unix socket path
heartbeatInterval?: number; // Heartbeat interval (ms)
timeout?: number; // Request timeout (ms)
debug?: boolean; // Enable debug logging
serializer?: "json" | "msgpack"; // Serialization format
}| Option | Type | Default | Description |
|---|---|---|---|
socketPath |
string | /tmp/bro-gateway.sock |
Unix socket file path |
heartbeatInterval |
number | 30000 |
How often to expect heartbeats (ms) |
timeout |
number | 30000 |
Request timeout duration (ms) |
debug |
boolean | false |
Enable debug logging (slower) |
serializer |
string | 'json' |
Message serialization format |
const server = new IPCServer({
socketPath: "/tmp/dev-gateway.sock",
debug: true,
heartbeatInterval: 10000, // Faster heartbeat
});const server = new IPCServer({
socketPath: "/var/run/bro-gateway.sock",
debug: false,
// serializer: 'msgpack', // I will implement this later for Faster serialization after implementation I will uncomment it
timeout: 60000, // Longer timeout
});const server = new IPCServer({
socketPath: "/tmp/test-gateway.sock",
debug: true,
timeout: 5000, // Shorter timeout
});The IPC Server is an EventEmitter and emits the following events:
Emitted when server starts successfully.
Payload:
{
socketPath: string;
}Example:
server.on("started", (data) => {
console.log(`Gateway listening on: ${data.socketPath}`);
});Emitted when server stops.
Example:
server.on("stopped", () => {
console.log("Gateway stopped");
});Emitted when a service connects and registers.
Payload:
{
serviceName: string;
methods: string[];
version?: string;
metadata?: object;
}Example:
server.on("service-registered", (data) => {
console.log(`Service registered: ${data.serviceName}`);
console.log(`Available methods: ${data.methods.join(", ")}`);
});Emitted when a service disconnects.
Payload:
{
serviceName: string;
}Example:
server.on("service-disconnected", (data) => {
console.log(`Service disconnected: ${data.serviceName}`);
// Maybe trigger alerts or restart service
});Emitted when a CALL message is routed.
Payload:
{
from: string;
to: string;
method: string;
requestId: string;
context: IPCContext;
}Example:
server.on("call-routed", (data) => {
console.log(`${data.from} → ${data.to}.${data.method}()`);
// Track metrics
metrics.increment("ipc.calls", {
from: data.from,
to: data.to,
method: data.method,
});
});Emitted when a RESPONSE message is routed.
Payload:
{
from: string;
to: string;
status: "success" | "error";
requestId: string;
}Example:
server.on("response-routed", (data) => {
console.log(`Response: ${data.from} → ${data.to} [${data.status}]`);
// Track success/error rates
metrics.increment(`ipc.responses.${data.status}`);
});Emitted when an error occurs.
Payload:
Error;Example:
server.on("error", (error) => {
console.error("Gateway error:", error);
// Log to monitoring system
logger.error("IPC Gateway Error", { error });
});Emitted for all log messages (regardless of debug setting).
Payload:
{
message: string;
data?: any;
timestamp: number;
}Example:
server.on("log", (logData) => {
// Send to external logging service
winston.info(logData.message, logData.data);
});import { IPCServer } from "./ipc/core/ipc-server";
async function startGateway() {
const server = new IPCServer({
socketPath: "/tmp/bro-gateway.sock",
debug: true,
});
// Listen to events
server.on("service-registered", (data) => {
console.log(`✓ ${data.serviceName} registered`);
});
server.on("call-routed", (data) => {
console.log(`→ ${data.from} calling ${data.to}.${data.method}()`);
});
// Start server
await server.start();
console.log("Gateway running!");
// Graceful shutdown
process.on("SIGTERM", async () => {
await server.stop();
process.exit(0);
});
}
startGateway();import { IPCServer } from "./ipc/core/ipc-server";
import { StatsD } from "hot-shots";
const statsd = new StatsD();
const server = new IPCServer({
socketPath: "/tmp/bro-gateway.sock",
debug: false,
});
// Track service connections
server.on("service-registered", (data) => {
statsd.increment("gateway.services.connected");
statsd.gauge("gateway.services.total", server.getConnectedServices().length);
});
server.on("service-disconnected", (data) => {
statsd.increment("gateway.services.disconnected");
statsd.gauge("gateway.services.total", server.getConnectedServices().length);
});
// Track message routing
server.on("call-routed", (data) => {
statsd.increment("gateway.calls.routed", {
from: data.from,
to: data.to,
});
});
server.on("response-routed", (data) => {
statsd.increment(`gateway.responses.${data.status}`);
});
await server.start();import { IPCServer } from "./ipc/core/ipc-server";
import express from "express";
const server = new IPCServer({
socketPath: "/tmp/bro-gateway.sock",
});
// HTTP health endpoint
const app = express();
app.get("/health", (req, res) => {
const status = server.getStatus();
res.json({
healthy: status.running,
services: status.services,
connectedServices: status.connectedServices,
});
});
app.get("/services", (req, res) => {
const services = server.getConnectedServices().map((name) => {
const service = server.getService(name);
return {
name: service.name,
methods: service.methods,
connectedAt: new Date(service.connectedAt).toISOString(),
lastHeartbeat: new Date(service.lastHeartbeat).toISOString(),
};
});
res.json({ services });
});
await server.start();
app.listen(3000);
console.log("Gateway running with health API on port 3000");import { IPCServer } from "./ipc/core/ipc-server";
async function startGateway() {
let server: IPCServer;
let restartCount = 0;
const maxRestarts = 5;
const start = async () => {
try {
server = new IPCServer({
socketPath: "/tmp/bro-gateway.sock",
debug: true,
});
server.on("error", async (error) => {
console.error("Gateway error:", error);
if (restartCount < maxRestarts) {
restartCount++;
console.log(`Restarting gateway (attempt ${restartCount})...`);
await server.stop();
await new Promise((resolve) => setTimeout(resolve, 5000));
await start();
} else {
console.error("Max restarts reached, giving up");
process.exit(1);
}
});
await server.start();
console.log("Gateway started");
restartCount = 0; // Reset on successful start
} catch (error) {
console.error("Failed to start gateway:", error);
process.exit(1);
}
};
await start();
}
startGateway();The IPC Client allows services to:
- Connect to the Gateway
- Register methods that can be called by other services
- Call methods on other services
- Handle automatic reconnection
- Track pending requests with promises
Service (Order/User/Cart)
|
IPCClient ────────> Gateway (/tmp/bro-gateway.sock)
|
(Your Methods)
1. Create IPCClient instance
↓
2. Register local methods (what this service can do)
↓
3. Connect to Gateway
↓
4. Send REGISTER message (tell Gateway about methods)
↓
5. Start heartbeat
↓
6. Ready to send/receive calls
// Making a call
Service A → client.call() → Gateway → Service B
↓
Service A ← Gateway ← Service B (response)
-------------------------------------------------
// Receiving a call
Service B ← Gateway ← Service A (incoming call)
↓
Execute method
↓
Service B → Gateway → Service A (send response)
import { IPCClient } from "./ipc/core/ipc-client";
// Create client
const client = new IPCClient({
serviceName: "order-service",
gatewayPath: "/tmp/bro-gateway.sock",
debug: true,
});
// Register methods this service provides
client.registerMethod("getOrderList", async (params, context) => {
console.log("Getting orders for user:", params.userId);
return [
{ id: 1, name: "Order #1" },
{ id: 2, name: "Order #2" },
];
});
// Connect to Gateway
await client.connect();
console.log("Connected to Gateway!");
// Call another service
const userData = await client.call("user-service", "getUserById", {
userId: "123",
});
console.log("User data:", userData);
// Later... disconnect
await client.disconnect();new IPCClient(config: IPCClientConfig)Creates a new IPC Client instance.
Parameters:
config: Client configuration object (required)
Example:
const client = new IPCClient({
serviceName: "order-service",
gatewayPath: "/tmp/bro-gateway.sock",
autoReconnect: true,
reconnectDelay: 5000,
timeout: 30000,
debug: false,
});Connects to the Gateway and registers the service.
Returns: Promise that resolves when connected and registered
Throws: IPCError if connection fails
Example:
try {
await client.connect();
console.log("✓ Connected to Gateway");
} catch (error) {
console.error("Failed to connect:", error);
}What it does:
- Creates socket connection
- Sends REGISTER message with service name and methods
- Waits for acknowledgment
- Starts heartbeat
- Emits
connectedevent
Disconnects from the Gateway gracefully.
Returns: Promise that resolves when disconnected
Example:
await client.disconnect();
console.log("Disconnected from Gateway");What it does:
- Stops heartbeat
- Rejects all pending requests
- Closes socket
- Clears state
- Emits
disconnectedevent
Registers a method that can be called by other services.
Parameters:
methodName: Name of the methodhandler: Async function that handles the method call
Example:
client.registerMethod("getUserById", async (params, context) => {
console.log("Getting user:", params.userId);
console.log("Call chain:", context.chain);
return {
id: params.userId,
name: "Nirikshan Bhusal",
email: "nirikshan@nirikshan.com",
};
});Handler Signature:
type MethodHandler = (params: any, context: IPCContext) => Promise;Removes a registered method.
Parameters:
methodName: Name of the method to remove
Example:
client.unregisterMethod("oldMethod");Calls a method on another service.
Parameters:
targetService: Name of the service to callmethod: Method name to executeparams: Parameters to passcontext(optional): Custom context (rarely needed)
Returns: Promise that resolves with the result
Throws: IPCError if call fails or times out
Example:
// Simple call
const user = await client.call("user-service", "getUserById", {
userId: "123",
});
// Typed call
interface User {
id: string;
name: string;
email: string;
}
const user = await client.call("user-service", "getUserById", {
userId: "123",
});
console.log(user.name); // TypeScript knows the type!Advanced Example:
try {
const result = await client.call("payment-service", "processPayment", {
orderId: "ORD-123",
amount: 99.99,
});
console.log("Payment processed:", result);
} catch (error) {
if (error.code === "TIMEOUT") {
console.error("Payment service timeout");
} else if (error.code === "SERVICE_NOT_FOUND") {
console.error("Payment service offline");
} else {
console.error("Payment failed:", error);
}
}Gets list of methods registered by this client.
Returns: Array of method names
Example:
const methods = client.getRegisteredMethods();
console.log("Available methods:", methods);
// Output: ['getUserById', 'createUser', 'updateUser']Checks if client is connected to the Gateway.
Returns: true if connected and registered, false otherwise
Example:
if (client.isConnected()) {
console.log("Ready to make calls");
} else {
console.log("Not connected to Gateway");
}Gets client status and statistics.
Returns: Status object
Example:
const status = client.getStatus();
console.log(status);
// Output:
// {
// connected: true,
// registered: true,
// serviceName: 'order-service',
// pendingRequests: 3,
// registeredMethods: 5
// }interface IPCClientConfig {
serviceName: string; // Required: Unique service name
gatewayPath: string; // Gateway socket path
autoReconnect?: boolean; // Auto-reconnect on disconnect
reconnectDelay?: number; // Reconnect delay (ms)
timeout?: number; // Request timeout (ms)
heartbeatInterval?: number; // Heartbeat interval (ms)
debug?: boolean; // Enable debug logging
// I will implement message pack later
// serializer?: string; // Serialization format
// poolSize?: number; // Connection pool size
}| Option | Type | Default | Description |
|---|---|---|---|
serviceName |
string | required | Unique name for this service |
gatewayPath |
string | /tmp/bro-gateway.sock |
Gateway socket path |
autoReconnect |
boolean | true |
Automatically reconnect on disconnect |
reconnectDelay |
number | 5000 |
Initial reconnect delay (ms) |
timeout |
number | 30000 |
Request timeout (ms) |
heartbeatInterval |
number | 30000 |
Heartbeat interval (ms) |
debug |
boolean | false |
Enable debug logging |
const client = new IPCClient({
serviceName: "order-service",
gatewayPath: "/tmp/dev-gateway.sock",
debug: true,
timeout: 10000, // Shorter timeout for faster feedback
});const client = new IPCClient({
serviceName: "order-service",
gatewayPath: "/var/run/bro-gateway.sock",
debug: false,
// serializer: 'msgpack', // Faster
autoReconnect: true,
timeout: 60000, // Longer timeout
});const client = new IPCClient({
serviceName: "order-service",
gatewayPath: "/tmp/bro-gateway.sock",
debug: false,
// I will implement this later pooling and msgpack
// serializer: 'msgpack',
// poolSize: 4, // 4 connections = higher throughput
});The IPC Client is an EventEmitter and emits the following events:
Emitted when successfully connected to Gateway.
Example:
client.on("connected", () => {
console.log("Connected to Gateway!");
});Emitted when disconnected from Gateway.
Example:
client.on("disconnected", () => {
console.warn("Disconnected from Gateway");
// Maybe notify admin or trigger alert
});Emitted when registration is acknowledged by Gateway.
Example:
client.on("registered", () => {
console.log("Service registered with Gateway");
});Emitted when a method is executed (called by another service).
Payload:
{
method: string;
requestId: string;
success: boolean;
error?: string;
}Example:
client.on("method-executed", (data) => {
console.log(
`Method executed: ${data.method} [${data.success ? "success" : "failed"}]`
);
// Track metrics
if (data.success) {
metrics.increment(`methods.${data.method}.success`);
} else {
metrics.increment(`methods.${data.method}.error`);
}
});Emitted when a response is received for a call.
Payload:
{
requestId: string;
success: boolean;
error?: string;
}Example:
client.on("response-received", (data) => {
console.log(`Response received: ${data.requestId} [${data.success}]`);
});Emitted when an error occurs.
Payload:
Error;Example:
client.on("error", (error) => {
console.error("IPC Client error:", error);
});Emitted when Gateway sends an error message.
Payload:
{
message: string;
code: string;
stack?: string;
}Example:
client.on("gateway-error", (error) => {
console.error("Gateway error:", error.message);
});Emitted for all log messages.
Payload:
{
serviceName: string;
message: string;
data?: any;
timestamp: number;
}Example:
client.on("log", (logData) => {
// Send to external logging
logger.info(logData.message, logData.data);
});import { IPCClient } from "./ipc/core/ipc-client";
async function startService() {
const client = new IPCClient({
serviceName: "user-service",
gatewayPath: "/tmp/bro-gateway.sock",
debug: true,
});
// Register method
client.registerMethod("getUserById", async (params, context) => {
console.log(`Getting user: ${params.userId}`);
console.log(`Called by: ${context.chain[context.chain.length - 2]}`);
// Simulate database lookup
return {
id: params.userId,
name: "Nirikshan Bhusal",
email: "nirikshan@nirikshan.com",
};
});
// Connect
await client.connect();
console.log("User service ready!");
// Graceful shutdown
process.on("SIGTERM", async () => {
await client.disconnect();
process.exit(0);
});
}
startService();import { IPCClient } from "./ipc/core/ipc-client";
async function startOrderService() {
const client = new IPCClient({
serviceName: "order-service",
gatewayPath: "/tmp/bro-gateway.sock",
});
// Register method that calls other services
client.registerMethod("getOrderDetails", async (params, context) => {
console.log(`[Depth ${context.depth}] Getting order: ${params.orderId}`);
// Get order from database
const order = {
id: params.orderId,
userId: "123",
items: ["item1", "item2"],
total: 99.99,
};
// Call User Service to get user info (nested call!)
const user = await client.call("user-service", "getUserById", {
userId: order.userId,
});
// Call Inventory Service to check stock
const inventory = await client.call("inventory-service", "checkStock", {
items: order.items,
});
return {
order,
user,
inventory,
};
});
await client.connect();
console.log("Order service ready!");
}
startOrderService();import { IPCClient } from "./ipc/core/ipc-client";
async function startPaymentService() {
const client = new IPCClient({
serviceName: "payment-service",
gatewayPath: "/tmp/bro-gateway.sock",
timeout: 60000, // Longer timeout for payment processing
});
client.registerMethod("processPayment", async (params, context) => {
try {
// Validate user exists
const user = await client.call("user-service", "getUserById", {
userId: params.userId,
});
if (!user) {
throw new Error("User not found");
}
// Validate order exists
const order = await client.call("order-service", "getOrderById", {
orderId: params.orderId,
});
if (!order) {
throw new Error("Order not found");
}
// Process payment (simulate)
console.log(`Processing payment: $${params.amount}`);
await new Promise((resolve) => setTimeout(resolve, 2000));
return {
success: true,
transactionId: `TXN-${Date.now()}`,
amount: params.amount,
};
} catch (error) {
console.error("Payment processing failed:", error);
// Return structured error
return {
success: false,
error: error.message,
};
}
});
await client.connect();
console.log("Payment service ready!");
}
startPaymentService();import { IPCClient } from "./ipc/core/ipc-client";
import { StatsD } from "hot-shots";
const statsd = new StatsD();
async function startService() {
const client = new IPCClient({
serviceName: "analytics-service",
gatewayPath: "/tmp/bro-gateway.sock",
});
// Track method execution
client.on("method-executed", (data) => {
const tags = { method: data.method, success: data.success };
statsd.increment("ipc.methods.executed", tags);
});
// Track outgoing calls
client.registerMethod("trackEvent", async (params, context) => {
const start = Date.now();
try {
// Store event
console.log("Tracking event:", params.event);
// Maybe call another service
if (params.userId) {
await client.call("user-service", "updateActivity", {
userId: params.userId,
activity: params.event,
});
}
const duration = Date.now() - start;
statsd.timing("ipc.methods.trackEvent.duration", duration);
return { success: true };
} catch (error) {
statsd.increment("ipc.methods.trackEvent.error");
throw error;
}
});
await client.connect();
}
startService();import { IPCClient } from "./ipc/core/ipc-client";
async function callWithRetry(
client: IPCClient,
service: string,
method: string,
params: any,
maxRetries: number = 3
): Promise {
let lastError: Error;
for (let attempt = 0; attempt <= maxRetries; attempt++) {
try {
if (attempt > 0) {
console.log(`Retry attempt ${attempt}/${maxRetries}`);
await new Promise((resolve) => setTimeout(resolve, 1000 * attempt));
}
return await client.call(service, method, params);
} catch (error) {
lastError = error;
// Don't retry on certain errors
if (
error.code === "METHOD_NOT_FOUND" ||
error.code === "SERVICE_NOT_FOUND"
) {
throw error;
}
console.warn(`Call failed (attempt ${attempt + 1}):`, error.message);
}
}
throw lastError;
}
// Usage
const client = new IPCClient({
serviceName: "order-service",
gatewayPath: "/tmp/bro-gateway.sock",
});
await client.connect();
// Call with automatic retry
const result = await callWithRetry(
client,
"flaky-service",
"getData",
{ id: "123" },
3 // Max 3 retries
);// GOOD - Unique names
new IPCClient({ serviceName: "order-service" });
new IPCClient({ serviceName: "user-service" });
// ❌ BAD - Duplicate names
new IPCClient({ serviceName: "service" }); // Too generic
new IPCClient({ serviceName: "service" }); // Conflict!// GOOD
client.registerMethod("getUser", handler);
client.registerMethod("createUser", handler);
await client.connect(); // Methods are sent during registration
// ❌ BAD
await client.connect();
client.registerMethod("getUser", handler); // Too late!// GOOD
try {
await client.connect();
console.log("Connected!");
} catch (error) {
console.error("Failed to connect:", error);
process.exit(1);
}
// ❌ BAD
await client.connect(); // Unhandled promise rejection!// GOOD
process.on("SIGTERM", async () => {
await client.disconnect();
process.exit(0);
});
// ❌ BAD
process.on("SIGTERM", () => {
process.exit(0); // Socket not closed!
});// GOOD - Type-safe
interface User {
id: string;
name: string;
}
const user = await client.call("user-service", "getUser", { id: "123" });
console.log(user.name); // TypeScript knows the type!
// ❌ BAD - No type safety
const user = await client.call("user-service", "getUser", { id: "123" });
console.log(user.name); // Could be undefined!// Development
new IPCClient({
serviceName: "order-service",
debug: true, // OK in dev
});
// Production
new IPCClient({
serviceName: "order-service",
debug: false, // REQUIRED for performance
});// Fast operations
new IPCClient({
serviceName: "cache-service",
timeout: 5000, // 5 seconds
});
// Slow operations
new IPCClient({
serviceName: "report-service",
timeout: 120000, // 2 minutes
});Cause: Forgot to call connect() or connection failed
Solution:
// Always check connection status
if (!client.isConnected()) {
console.error("Not connected!");
await client.connect();
}
await client.call("user-service", "getUser", {});Cause: Target service not connected or wrong name
Solution:
// Check service name is correct
await client.call("user-service", "getUser", {}); // Correct
await client.call("userservice", "getUser", {}); // ❌ Wrong nameCause: Method not registered on target service
Solution:
// Check method name and ensure it's registered
client.registerMethod("getUserById", handler); // Registered
await client.call("user-service", "getUserById", {}); // Correct
await client.call("user-service", "getUser", {}); // ❌ Wrong nameCause: Target service too slow or not responding
Solution:
// Increase timeout for slow operations
const client = new IPCClient({
serviceName: "order-service",
timeout: 60000, // 60 seconds
});
// Or handle timeout errors
try {
await client.call("slow-service", "heavyOperation", {});
} catch (error) {
if (error.code === "TIMEOUT") {
console.error("Operation timed out");
}
}Cause: Network issues or Gateway restart
Solution:
// Enable auto-reconnect
const client = new IPCClient({
serviceName: "order-service",
autoReconnect: true, // Enabled
reconnectDelay: 5000,
});
// Listen to reconnection events
client.on("disconnected", () => {
console.warn("Lost connection to Gateway");
});
client.on("connected", () => {
console.log("Reconnected to Gateway!");
});- Cache frequently-accessed data
MIT
Contributions welcome! Please read readme.md first.