fix(readme): Update README: expand docs, examples, server readiness, heartbeat, and testing utilities

This commit is contained in:
2025-08-25 14:00:56 +00:00
parent d52fa80650
commit f1534ad531
3 changed files with 390 additions and 261 deletions

View File

@@ -1,5 +1,16 @@
# Changelog
## 2025-08-25 - 2.1.1 - fix(readme)
Update README: expand docs, examples, server readiness, heartbeat, and testing utilities
- Rewrite introduction and overall tone to emphasize zero-dependency, reliability, and TypeScript support
- Replace several Quick Start examples to use socketPath and show autoCleanupSocketFile usage
- Add Server readiness detection docs and SmartIpc.waitForServer example
- Document smart connection retry options (connectRetry) and registerTimeoutMs usage
- Clarify heartbeat configuration and add heartbeatThrowOnTimeout option to emit events instead of throwing
- Add sections for automatic socket cleanup, broadcasting, testing utilities (waitForServer, spawnAndConnect), and metrics
- Various formatting and copy improvements throughout README
## 2025-08-25 - 2.1.0 - feat(core)
Add heartbeat grace/timeout options, client retry/wait-for-ready, server readiness and socket cleanup, transport socket options, helper utilities, and tests

620
readme.md
View File

@@ -1,34 +1,33 @@
# @push.rocks/smartipc 🚀
**Lightning-fast, type-safe IPC for modern Node.js applications**
**Rock-solid IPC for Node.js with zero dependencies**
[![npm version](https://img.shields.io/npm/v/@push.rocks/smartipc.svg)](https://www.npmjs.com/package/@push.rocks/smartipc)
[![TypeScript](https://img.shields.io/badge/TypeScript-5.x-blue.svg)](https://www.typescriptlang.org/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./license)
SmartIPC is a production-grade Inter-Process Communication library that brings enterprise-level messaging patterns to Node.js. Built with TypeScript from the ground up, it offers zero-dependency native IPC with automatic reconnection, type-safe messaging, and built-in observability.
SmartIPC delivers bulletproof Inter-Process Communication for Node.js applications. Built for real-world production use, it handles all the edge cases that make IPC tricky - automatic reconnection, race conditions, heartbeat monitoring, and clean shutdowns. All with **zero external dependencies** and full TypeScript support.
## Why SmartIPC?
## 🎯 Why SmartIPC?
- **🎯 Zero External Dependencies** - Pure Node.js implementation using native `net` module
- **🔒 Type-Safe** - Full TypeScript support with generics for compile-time safety
- **🔄 Auto-Reconnect** - Built-in exponential backoff and circuit breaker patterns
- **📊 Observable** - Real-time metrics and connection tracking
- **⚡ High Performance** - Length-prefixed framing, backpressure handling, and optimized buffers
- **🎭 Multiple Patterns** - Request/Response, Pub/Sub, and Fire-and-Forget messaging
- **🛡️ Production Ready** - Message size limits, heartbeat monitoring, and graceful shutdown
- **Zero Dependencies** - Pure Node.js implementation using native modules
- **Battle-tested Reliability** - Automatic reconnection, graceful degradation, and timeout handling
- **Type-Safe** - Full TypeScript support with generics for compile-time safety
- **CI/Test Ready** - Built-in helpers and race condition prevention for testing
- **Observable** - Real-time metrics, connection tracking, and health monitoring
- **Multiple Patterns** - Request/Response, Pub/Sub, and Fire-and-Forget messaging
## Installation
## 📦 Installation
```bash
npm install @push.rocks/smartipc
# or
pnpm add @push.rocks/smartipc
# or
npm install @push.rocks/smartipc
yarn add @push.rocks/smartipc
```
## Quick Start
### Simple TCP Server & Client
## 🚀 Quick Start
```typescript
import { SmartIpc } from '@push.rocks/smartipc';
@@ -36,34 +35,42 @@ import { SmartIpc } from '@push.rocks/smartipc';
// Create a server
const server = SmartIpc.createServer({
id: 'my-service',
host: 'localhost',
port: 9876
socketPath: '/tmp/my-service.sock',
autoCleanupSocketFile: true // Clean up stale sockets automatically
});
// Handle incoming messages
server.onMessage('hello', async (data, clientId) => {
console.log(`Client ${clientId} says:`, data);
return { response: 'Hello back!' };
server.onMessage('greet', async (data, clientId) => {
console.log(`Client ${clientId} says:`, data.message);
return { response: `Hello ${data.name}!` };
});
await server.start();
// Start the server
await server.start({ readyWhen: 'accepting' }); // Wait until fully ready
console.log('Server is ready to accept connections! ✨');
// Create a client
const client = SmartIpc.createClient({
id: 'my-service',
host: 'localhost',
port: 9876,
clientId: 'client-1'
socketPath: '/tmp/my-service.sock',
connectRetry: {
enabled: true,
maxAttempts: 10
}
});
// Connect with automatic retry
await client.connect();
// Send a message and get response
const response = await client.request('hello', { message: 'Hi server!' });
console.log('Server responded:', response);
// Send a request and get a response
const response = await client.request('greet', {
name: 'World',
message: 'Hi there!'
});
console.log('Server said:', response.response); // "Hello World!"
```
## Core Concepts
## 🎮 Core Concepts
### Transport Types
@@ -84,348 +91,394 @@ const unixServer = SmartIpc.createServer({
});
// Windows Named Pipe (Windows optimal)
const pipeServer = SmartIpc.createServer({
// Automatically used on Windows when socketPath is provided
const windowsServer = SmartIpc.createServer({
id: 'pipe-service',
pipeName: 'my-app-pipe'
socketPath: '\\\\.\\pipe\\my-app-pipe'
});
```
### Message Patterns
#### 🔥 Fire and Forget
Fast, one-way messaging when you don't need a response:
Send messages without waiting for a response:
```typescript
// Server
server.onMessage('log', (data, clientId) => {
console.log(`[${clientId}]:`, data.message);
// No return value needed
console.log(`[${clientId}] ${data.level}:`, data.message);
// No return needed
});
// Client
await client.sendMessage('log', {
level: 'info',
message: 'User logged in',
timestamp: Date.now()
});
```
#### 📞 Request/Response
RPC-style communication with timeouts and type safety:
RPC-style communication with type safety:
```typescript
// Server - Define your handler with types
interface CalculateRequest {
operation: 'add' | 'multiply';
values: number[];
interface UserRequest {
userId: string;
fields?: string[];
}
interface CalculateResponse {
result: number;
computedAt: number;
interface UserResponse {
id: string;
name: string;
email?: string;
createdAt: number;
}
server.onMessage<CalculateRequest, CalculateResponse>('calculate', async (data) => {
const result = data.operation === 'add'
? data.values.reduce((a, b) => a + b, 0)
: data.values.reduce((a, b) => a * b, 1);
// Server
server.onMessage<UserRequest, UserResponse>('getUser', async (data) => {
const user = await db.getUser(data.userId);
return {
result,
computedAt: Date.now()
id: user.id,
name: user.name,
email: data.fields?.includes('email') ? user.email : undefined,
createdAt: user.createdAt
};
});
// Client - Type-safe request
const response = await client.request<CalculateRequest, CalculateResponse>(
'calculate',
{ operation: 'add', values: [1, 2, 3, 4, 5] },
// Client - with timeout
const user = await client.request<UserRequest, UserResponse>(
'getUser',
{ userId: '123', fields: ['email'] },
{ timeout: 5000 }
);
console.log(`Sum is ${response.result}`);
```
#### 📢 Pub/Sub Pattern
Topic-based message broadcasting:
```typescript
// Server automatically handles subscriptions
const publisher = SmartIpc.createClient({
id: 'events-service',
clientId: 'publisher'
});
// Subscribers
const subscriber1 = SmartIpc.createClient({
id: 'events-service',
clientId: 'subscriber-1'
socketPath: '/tmp/events.sock'
});
const subscriber2 = SmartIpc.createClient({
id: 'events-service',
clientId: 'subscriber-2'
});
// Subscribe to topics
await subscriber1.connect();
await subscriber1.subscribe('user.login', (data) => {
console.log('User logged in:', data);
});
await subscriber2.subscribe('user.*', (data) => {
console.log('User event:', data);
// Publisher
const publisher = SmartIpc.createClient({
id: 'events-service',
socketPath: '/tmp/events.sock'
});
// Publish events
await publisher.connect();
await publisher.publish('user.login', {
userId: '123',
ip: '192.168.1.1',
timestamp: Date.now()
});
```
## Advanced Features
## 💪 Advanced Features
### 🔄 Auto-Reconnection with Exponential Backoff
### 🏁 Server Readiness Detection
Clients automatically reconnect on connection loss:
Eliminate race conditions in tests and production:
```typescript
const server = SmartIpc.createServer({
id: 'my-service',
socketPath: '/tmp/my-service.sock',
autoCleanupSocketFile: true
});
// Option 1: Wait for full readiness
await server.start({ readyWhen: 'accepting' });
// Server is now FULLY ready to accept connections
// Option 2: Use ready event
server.on('ready', () => {
console.log('Server is ready!');
startClients();
});
await server.start();
// Option 3: Check readiness state
if (server.getIsReady()) {
console.log('Ready to rock! 🎸');
}
```
### 🔄 Smart Connection Retry
Never lose messages due to temporary connection issues:
```typescript
const client = SmartIpc.createClient({
id: 'resilient-service',
clientId: 'auto-reconnect-client',
reconnect: {
id: 'resilient-client',
socketPath: '/tmp/service.sock',
connectRetry: {
enabled: true,
initialDelay: 1000, // Start with 1 second
maxDelay: 30000, // Cap at 30 seconds
factor: 2, // Double each time
maxAttempts: Infinity // Keep trying forever
}
initialDelay: 100, // Start with 100ms
maxDelay: 1500, // Cap at 1.5 seconds
maxAttempts: 20, // Try 20 times
totalTimeout: 15000 // Give up after 15 seconds total
},
registerTimeoutMs: 8000 // Registration handshake timeout
});
// Monitor connection state
client.on('connected', () => console.log('Connected! 🟢'));
client.on('disconnected', () => console.log('Connection lost! 🔴'));
client.on('reconnecting', (attempt) => console.log(`Reconnecting... Attempt ${attempt} 🟡`));
// Will retry automatically if server isn't ready yet
await client.connect({
waitForReady: true, // Wait for server to exist
waitTimeout: 10000 // Wait up to 10 seconds
});
```
### 💓 Heartbeat Monitoring
### 💓 Graceful Heartbeat Monitoring
Keep connections alive and detect failures quickly:
Keep connections alive without crashing on timeouts:
```typescript
const server = SmartIpc.createServer({
id: 'monitored-service',
heartbeat: {
enabled: true,
interval: 5000, // Send heartbeat every 5 seconds
timeout: 15000 // Consider dead after 15 seconds
}
socketPath: '/tmp/monitored.sock',
heartbeat: true,
heartbeatInterval: 3000,
heartbeatTimeout: 10000,
heartbeatInitialGracePeriodMs: 5000, // Grace period for startup
heartbeatThrowOnTimeout: false // Emit event instead of throwing
});
// Clients automatically respond to heartbeats
server.on('heartbeatTimeout', (clientId) => {
console.log(`Client ${clientId} heartbeat timeout - will handle gracefully`);
});
// Client configuration
const client = SmartIpc.createClient({
id: 'monitored-service',
clientId: 'heartbeat-client',
heartbeat: true // Enable heartbeat responses
socketPath: '/tmp/monitored.sock',
heartbeat: true,
heartbeatInterval: 3000,
heartbeatTimeout: 10000,
heartbeatInitialGracePeriodMs: 5000,
heartbeatThrowOnTimeout: false
});
client.on('heartbeatTimeout', () => {
console.log('Heartbeat timeout detected, reconnecting...');
// Handle reconnection logic
});
```
### 📊 Real-time Metrics & Observability
### 🧹 Automatic Socket Cleanup
Track performance and connection health:
Never worry about stale socket files:
```typescript
// Server metrics
const server = SmartIpc.createServer({
id: 'clean-service',
socketPath: '/tmp/service.sock',
autoCleanupSocketFile: true, // Remove stale socket on start
socketMode: 0o600 // Set socket permissions (Unix only)
});
// Socket file will be cleaned up automatically on start
await server.start();
```
### 📊 Real-time Metrics
Monitor your IPC performance:
```typescript
// Server stats
const serverStats = server.getStats();
console.log({
isRunning: serverStats.isRunning,
connectedClients: serverStats.connectedClients,
totalConnections: serverStats.totalConnections,
uptime: serverStats.uptime,
metrics: {
messagesSent: serverStats.metrics.messagesSent,
messagesReceived: serverStats.metrics.messagesReceived,
bytesSent: serverStats.metrics.bytesSent,
bytesReceived: serverStats.metrics.bytesReceived,
errors: serverStats.metrics.errors
}
});
// Client metrics
// Client stats
const clientStats = client.getStats();
console.log({
connected: clientStats.connected,
reconnectAttempts: clientStats.reconnectAttempts,
lastActivity: clientStats.lastActivity,
metrics: clientStats.metrics
});
// Track specific clients on server
const clientInfo = server.getClientInfo('client-1');
// Get specific client info
const clientInfo = server.getClientInfo('client-123');
console.log({
clientId: clientInfo.clientId,
metadata: clientInfo.metadata,
connectedAt: clientInfo.connectedAt,
lastActivity: clientInfo.lastActivity,
subscriptions: clientInfo.subscriptions
connectedAt: new Date(clientInfo.connectedAt),
lastActivity: new Date(clientInfo.lastActivity),
metadata: clientInfo.metadata
});
```
### 🛡️ Security & Limits
### 🎯 Broadcasting
Protect against malicious or misbehaving clients:
```typescript
const secureServer = SmartIpc.createServer({
id: 'secure-service',
maxMessageSize: 10 * 1024 * 1024, // 10MB max message size
maxConnections: 100, // Limit concurrent connections
connectionTimeout: 60000, // Drop idle connections after 1 minute
// Authentication (coming soon)
auth: {
required: true,
validator: async (token) => {
// Validate auth token
return validateToken(token);
}
}
});
// Rate limiting per client
secureServer.use(rateLimitMiddleware({
windowMs: 60000, // 1 minute window
max: 100 // 100 requests per window
}));
```
### 🎯 Broadcast to Specific Clients
Send targeted messages:
Send messages to multiple clients:
```typescript
// Broadcast to all connected clients
server.broadcast('system-alert', {
message: 'Maintenance in 5 minutes'
await server.broadcast('announcement', {
message: 'Server will restart in 5 minutes',
severity: 'warning'
});
// Send to specific client
server.sendToClient('client-1', 'personal-message', {
content: 'This is just for you'
});
// Send to specific clients
await server.broadcastTo(
['client-1', 'client-2'],
'private-message',
{ content: 'This is just for you two' }
);
// Send to multiple specific clients
server.sendToClients(['client-1', 'client-2'], 'group-message', {
content: 'Group notification'
// Send to one client
await server.sendToClient('client-1', 'direct', {
data: 'Personal message'
});
// Get all connected client IDs
const clients = server.getConnectedClients();
console.log('Connected clients:', clients);
```
## Error Handling
## 🧪 Testing Utilities
Comprehensive error handling with typed errors:
SmartIPC includes powerful helpers for testing:
### Wait for Server
```typescript
import { IpcError, ConnectionError, TimeoutError } from '@push.rocks/smartipc';
import { SmartIpc } from '@push.rocks/smartipc';
// Client error handling
// Start your server in another process
const serverProcess = spawn('node', ['server.js']);
// Wait for it to be ready
await SmartIpc.waitForServer({
socketPath: '/tmp/test.sock',
timeoutMs: 10000
});
// Now safe to connect clients
const client = SmartIpc.createClient({
id: 'test-client',
socketPath: '/tmp/test.sock'
});
await client.connect();
```
### Spawn and Connect
```typescript
// Helper that spawns a server and connects a client
const { client, serverProcess } = await SmartIpc.spawnAndConnect({
serverScript: './server.js',
socketPath: '/tmp/test.sock',
clientId: 'test-client',
connectRetry: {
enabled: true,
maxAttempts: 10
}
});
// Use the client
const response = await client.request('ping', {});
// Cleanup
await client.disconnect();
serverProcess.kill();
```
## 🎭 Event Handling
SmartIPC provides comprehensive event emitters:
```typescript
// Server events
server.on('start', () => console.log('Server started'));
server.on('ready', () => console.log('Server ready for connections'));
server.on('clientConnect', (clientId, metadata) => {
console.log(`Client ${clientId} connected with metadata:`, metadata);
});
server.on('clientDisconnect', (clientId) => {
console.log(`Client ${clientId} disconnected`);
});
server.on('error', (error, clientId) => {
console.error(`Error from ${clientId}:`, error);
});
// Client events
client.on('connect', () => console.log('Connected to server'));
client.on('disconnect', () => console.log('Disconnected from server'));
client.on('reconnecting', (attempt) => {
console.log(`Reconnection attempt ${attempt}`);
});
client.on('error', (error) => {
if (error instanceof ConnectionError) {
console.error('Connection failed:', error.message);
} else if (error instanceof TimeoutError) {
console.error('Request timed out:', error.message);
console.error('Client error:', error);
});
client.on('heartbeatTimeout', (error) => {
console.warn('Heartbeat timeout:', error);
});
```
## 🛡️ Error Handling
Robust error handling with detailed error information:
```typescript
// Client-side error handling
try {
const response = await client.request('riskyOperation', data, {
timeout: 5000
});
} catch (error) {
if (error.message.includes('timeout')) {
console.error('Request timed out');
} else if (error.message.includes('Failed to register')) {
console.error('Could not register with server');
} else {
console.error('Unknown error:', error);
}
});
// Server error handling
server.on('client-error', (clientId, error) => {
console.error(`Client ${clientId} error:`, error);
// Optionally disconnect misbehaving clients
if (error.code === 'INVALID_MESSAGE') {
server.disconnectClient(clientId);
}
});
// Request with error handling
// Server-side error boundaries
server.onMessage('process', async (data, clientId) => {
try {
const response = await client.request('risky-operation', data, {
timeout: 5000,
retries: 3
});
return await riskyProcessing(data);
} catch (error) {
if (error instanceof TimeoutError) {
// Handle timeout
} else {
// Handle other errors
console.error(`Processing failed for ${clientId}:`, error);
throw error; // Will be sent back to client as error
}
}
```
## Testing
SmartIPC includes comprehensive testing utilities:
```typescript
import { createTestServer, createTestClient } from '@push.rocks/smartipc/testing';
describe('My IPC integration', () => {
let server, client;
beforeEach(async () => {
server = await createTestServer();
client = await createTestClient(server);
});
afterEach(async () => {
await client.disconnect();
await server.stop();
});
it('should handle messages', async () => {
server.onMessage('test', (data) => ({ echo: data }));
const response = await client.request('test', { value: 42 });
expect(response.echo.value).toBe(42);
});
});
```
## Performance Benchmarks
## 🏗️ Architecture
SmartIPC has been optimized for high throughput and low latency:
| Transport | Messages/sec | Avg Latency | Use Case |
|-----------|-------------|-------------|----------|
| Unix Socket | 150,000+ | < 0.1ms | Local high-performance IPC |
| TCP (localhost) | 100,000+ | < 0.2ms | Local network-capable IPC |
| TCP (network) | 50,000+ | < 1ms | Distributed systems |
| Named Pipe | 120,000+ | < 0.15ms | Windows local IPC |
*Benchmarked on modern hardware with 1KB message payloads*
## Architecture
SmartIPC uses a layered architecture for maximum flexibility:
SmartIPC uses a clean, layered architecture:
```
┌─────────────────────────────────────────┐
│ Application Layer
(Your business logic and handlers)
Your Application │
(Business logic)
└─────────────────────────────────────────┘
┌─────────────────────────────────────────┐
IPC Client / Server
│ (High-level API, patterns, routing) │
IpcServer / IpcClient
│ (High-level API, Message routing)
└─────────────────────────────────────────┘
┌─────────────────────────────────────────┐
│ IPC Channel │
│ (Connection management, reconnection,
heartbeat, request/response)
│ IpcChannel
│ (Connection management, Heartbeat,
Reconnection, Request/Response) │
└─────────────────────────────────────────┘
┌─────────────────────────────────────────┐
@@ -435,25 +488,94 @@ SmartIPC uses a layered architecture for maximum flexibility:
└─────────────────────────────────────────┘
```
## Comparison with Alternatives
## 🎯 Common Use Cases
| Feature | SmartIPC | node-ipc | zeromq | |
|---------|----------|----------|---------|--|
| Zero Dependencies | | | | |
| TypeScript Native | | | | |
| Auto-Reconnect | | | | |
| Request/Response | | | | |
| Pub/Sub | | | | |
| Built-in Metrics | | | | |
| Heartbeat | | | | |
| Message Size Limits | | | | |
| Type Safety | | | | |
### Microservices Communication
```typescript
// API Gateway
const gateway = SmartIpc.createServer({
id: 'api-gateway',
socketPath: '/tmp/gateway.sock'
});
## Support
// User Service
const userService = SmartIpc.createClient({
id: 'api-gateway',
socketPath: '/tmp/gateway.sock',
clientId: 'user-service'
});
- 📖 [Documentation](https://code.foss.global/push.rocks/smartipc)
- 🐛 [Issue Tracker](https://code.foss.global/push.rocks/smartipc/issues)
- 💬 [Discussions](https://code.foss.global/push.rocks/smartipc/discussions)
// Order Service
const orderService = SmartIpc.createClient({
id: 'api-gateway',
socketPath: '/tmp/gateway.sock',
clientId: 'order-service'
});
```
### Worker Process Management
```typescript
// Main process
const server = SmartIpc.createServer({
id: 'main',
socketPath: '/tmp/workers.sock'
});
server.onMessage('job-complete', (result, workerId) => {
console.log(`Worker ${workerId} completed job:`, result);
});
// Worker process
const worker = SmartIpc.createClient({
id: 'main',
socketPath: '/tmp/workers.sock',
clientId: `worker-${process.pid}`
});
await worker.sendMessage('job-complete', {
jobId: '123',
result: processedData
});
```
### Real-time Event Distribution
```typescript
// Event bus
const eventBus = SmartIpc.createServer({
id: 'event-bus',
socketPath: '/tmp/events.sock'
});
// Services subscribe to events
const analyticsService = SmartIpc.createClient({
id: 'event-bus',
socketPath: '/tmp/events.sock'
});
await analyticsService.subscribe('user.*', (event) => {
trackEvent(event);
});
```
## 📈 Performance
SmartIPC is optimized for high throughput and low latency:
| Transport | Messages/sec | Avg Latency | Use Case |
|-----------|-------------|-------------|----------|
| Unix Socket | 150,000+ | < 0.1ms | Local high-performance IPC (Linux/macOS) |
| Named Pipe | 120,000+ | < 0.15ms | Windows local IPC |
| TCP (localhost) | 100,000+ | < 0.2ms | Local network-capable IPC |
| TCP (network) | 50,000+ | < 1ms | Distributed systems |
- **Memory efficient**: Streaming support for large payloads
- **CPU efficient**: Event-driven, non-blocking I/O
## 🔧 Requirements
- Node.js >= 14.x
- TypeScript >= 4.x (for development)
- Unix-like OS (Linux, macOS) or Windows
## License and Legal Information
@@ -473,7 +595,3 @@ Registered at District court Bremen HRB 35230 HB, Germany
For any legal inquiries or if you require further information, please contact us via email at hello@task.vc.
By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.
---
**Built with by Task Venture Capital GmbH**

View File

@@ -3,6 +3,6 @@
*/
export const commitinfo = {
name: '@push.rocks/smartipc',
version: '2.1.0',
version: '2.1.1',
description: 'A library for node inter process communication, providing an easy-to-use API for IPC.'
}