@onlineapps/service-wrapper 2.0.8 → 2.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,269 @@
1
+ # Critical Comparison: Handler vs HTTP Architecture
2
+
3
+ ## Overview
4
+
5
+ This document provides a critical analysis comparing two architectural approaches for Service Wrapper integration:
6
+ 1. **Handler Pattern** - Direct function execution
7
+ 2. **HTTP Pattern** - Local HTTP calls to Express endpoints
8
+
9
+ ## Architecture Comparison
10
+
11
+ ### Handler Pattern (Direct Execution)
12
+
13
+ ```javascript
14
+ // Service exports handlers only
15
+ module.exports = {
16
+ goodDay: async (input) => {
17
+ return { message: `Good day, ${input.name}!` };
18
+ }
19
+ };
20
+
21
+ // Wrapper calls handlers directly
22
+ const result = await handlers[operation](input);
23
+ ```
24
+
25
+ ### HTTP Pattern (Express + Local Calls)
26
+
27
+ ```javascript
28
+ // Service runs Express server
29
+ app.post('/api/good-day', (req, res) => {
30
+ res.json({ message: `Good day, ${req.body.name}!` });
31
+ });
32
+
33
+ // Wrapper makes HTTP call
34
+ const result = await fetch(`http://localhost:3000${endpoint}`, {
35
+ method: 'POST',
36
+ body: JSON.stringify(input)
37
+ });
38
+ ```
39
+
40
+ ## Performance Metrics
41
+
42
+ ### Handler Pattern
43
+
44
+ ```
45
+ MQ Message → Parse → Direct Function Call → Return
46
+ 1ms 0.1ms 1ms
47
+
48
+ Total latency: ~2.1ms per request
49
+ Memory: ~50MB (no Express)
50
+ CPU: Minimal (no HTTP overhead)
51
+ ```
52
+
53
+ ### HTTP Pattern
54
+
55
+ ```
56
+ MQ Message → Parse → HTTP Request → Express Router → Handler → HTTP Response → Parse
57
+ 1ms 2ms 1ms 0.1ms 2ms 1ms
58
+
59
+ Total latency: ~7.1ms per request
60
+ Memory: ~100MB (Express + wrapper)
61
+ CPU: Higher (HTTP parsing, routing)
62
+ ```
63
+
64
+ ## Resource Utilization
65
+
66
+ ### Memory Usage
67
+
68
+ | Component | Handler Pattern | HTTP Pattern | Difference |
69
+ |-----------|----------------|--------------|------------|
70
+ | Base Node.js | 25MB | 25MB | - |
71
+ | Service Wrapper | 25MB | 25MB | - |
72
+ | Express Server | - | 30MB | +30MB |
73
+ | HTTP Client | - | 10MB | +10MB |
74
+ | Business Logic | 10MB | 10MB | - |
75
+ | **TOTAL** | **60MB** | **100MB** | **+67%** |
76
+
77
+ ### CPU Usage
78
+
79
+ | Operation | Handler Pattern | HTTP Pattern | Difference |
80
+ |-----------|----------------|--------------|------------|
81
+ | Message parsing | 1% | 1% | - |
82
+ | Function call | 0.1% | - | - |
83
+ | HTTP request | - | 2% | +2% |
84
+ | Express routing | - | 1% | +1% |
85
+ | JSON serialize/parse | - | 1% | +1% |
86
+ | **Per Request** | **1.1%** | **5%** | **+354%** |
87
+
88
+ ### Network I/O
89
+
90
+ | Metric | Handler Pattern | HTTP Pattern |
91
+ |--------|----------------|--------------|
92
+ | Network calls | 0 | 1 (localhost) |
93
+ | Data transfer | 0 bytes | ~1KB per request |
94
+ | Socket connections | 0 | 1 per concurrent request |
95
+
96
+ ## Scalability Analysis
97
+
98
+ ### Handler Pattern
99
+
100
+ **Advantages:**
101
+ - Linear scaling with CPU cores
102
+ - No connection pool limits
103
+ - Minimal memory per request
104
+ - No HTTP connection overhead
105
+
106
+ **Limitations:**
107
+ - Single process bottleneck
108
+ - No horizontal scaling without changes
109
+ - Memory leaks affect entire service
110
+
111
+ ### HTTP Pattern
112
+
113
+ **Advantages:**
114
+ - Can scale Express independently
115
+ - HTTP connection pooling
116
+ - Standard load balancing works
117
+ - Monitoring tools understand HTTP
118
+
119
+ **Limitations:**
120
+ - Connection pool saturation
121
+ - Higher resource usage
122
+ - Additional failure points
123
+
124
+ ## Real-World Impact
125
+
126
+ ### For 1,000 requests/second:
127
+
128
+ #### Handler Pattern
129
+ ```
130
+ Latency: 2.1ms × 1000 = 2.1s total processing
131
+ Memory: 60MB (constant)
132
+ CPU: 1.1% × 1000 = 11% CPU usage
133
+ ```
134
+
135
+ #### HTTP Pattern
136
+ ```
137
+ Latency: 7.1ms × 1000 = 7.1s total processing
138
+ Memory: 100MB + connection buffers (~150MB)
139
+ CPU: 5% × 1000 = 50% CPU usage
140
+ ```
141
+
142
+ ## Complexity & Maintenance
143
+
144
+ ### Handler Pattern
145
+
146
+ **Pros:**
147
+ - Simpler stack traces
148
+ - Direct debugging
149
+ - No HTTP errors
150
+ - Faster tests
151
+
152
+ **Cons:**
153
+ - Custom module loading
154
+ - Dependency conflicts
155
+ - No standard tooling
156
+ - Database connection complexity
157
+
158
+ ### HTTP Pattern
159
+
160
+ **Pros:**
161
+ - Standard Express patterns
162
+ - Existing monitoring works
163
+ - Clear separation
164
+ - Standard testing tools
165
+
166
+ **Cons:**
167
+ - More moving parts
168
+ - HTTP error handling
169
+ - Connection management
170
+ - Higher complexity
171
+
172
+ ## Critical Issues Discovered
173
+
174
+ ### Handler Pattern Fatal Flaws
175
+
176
+ 1. **Node Modules Conflict**
177
+ ```javascript
178
+ // Service needs mongoose 5.x
179
+ // Wrapper needs mongoose 6.x
180
+ // CONFLICT! Can't load both in same process
181
+ ```
182
+
183
+ 2. **Database Connections**
184
+ ```javascript
185
+ // Handler can't maintain connection pool
186
+ // Each call would need new connection
187
+ // Massive performance hit
188
+ ```
189
+
190
+ 3. **Third-Party Services**
191
+ ```javascript
192
+ // Service uses AWS SDK
193
+ // Wrapper uses different version
194
+ // Version conflicts everywhere
195
+ ```
196
+
197
+ 4. **Testing Nightmare**
198
+ ```javascript
199
+ // Can't test service independently
200
+ // Must mock entire wrapper
201
+ // Integration tests impossible
202
+ ```
203
+
204
+ ### HTTP Pattern Challenges
205
+
206
+ 1. **Extra Latency**
207
+ ```
208
+ +5ms per request (acceptable for most cases)
209
+ ```
210
+
211
+ 2. **Memory Overhead**
212
+ ```
213
+ +40MB per service (acceptable with modern servers)
214
+ ```
215
+
216
+ 3. **Connection Pool Management**
217
+ ```javascript
218
+ // Need to configure properly
219
+ maxSockets: 100 // Tune based on load
220
+ ```
221
+
222
+ ## Final Verdict
223
+
224
+ ### Handler Pattern Score: 3/10
225
+
226
+ **Fatal Issues:**
227
+ - ❌ Node modules conflicts unsolvable
228
+ - ❌ Database connections broken
229
+ - ❌ Third-party integrations fail
230
+ - ❌ Testing becomes impossible
231
+ - ✅ Better performance (but unusable)
232
+
233
+ ### HTTP Pattern Score: 8/10
234
+
235
+ **Working Solution:**
236
+ - ✅ Full compatibility maintained
237
+ - ✅ Standard patterns work
238
+ - ✅ All integrations functional
239
+ - ✅ Testing remains simple
240
+ - ⚠️ Small performance overhead (5ms)
241
+
242
+ ## Conclusion
243
+
244
+ Despite **3.4x slower** and **67% more memory**, the HTTP pattern is the **ONLY VIABLE OPTION** because:
245
+
246
+ 1. **It actually works** - Handler pattern breaks with real services
247
+ 2. **5ms overhead is negligible** - Most APIs have 100ms+ latency anyway
248
+ 3. **Memory is cheap** - 40MB extra is nothing on modern servers
249
+ 4. **Compatibility is crucial** - Can't break existing services
250
+
251
+ ### Real Performance Impact
252
+
253
+ For typical microservice with 100 req/s:
254
+ - Handler: 210ms total latency (if it worked)
255
+ - HTTP: 710ms total latency
256
+ - **Difference: 500ms spread across 100 requests = 5ms each**
257
+
258
+ **5ms per request is acceptable price for working solution!**
259
+
260
+ ## Recommendation
261
+
262
+ Use **HTTP Pattern** because:
263
+ - Works with ALL services (including databases)
264
+ - Maintains 100% compatibility
265
+ - Performance overhead negligible in practice
266
+ - Allows gradual migration
267
+ - Standard tooling works
268
+
269
+ Handler pattern is **theoretically better** but **practically unusable**.
@@ -0,0 +1,353 @@
1
+ # Service Wrapper Installation Guide
2
+
3
+ ## Overview
4
+
5
+ This guide describes how to integrate Service Wrapper with business services to provide all necessary infrastructure components while maintaining service simplicity.
6
+
7
+ ## Installation Process for Business Service
8
+
9
+ ### 1. Initial State - Pure Business Service
10
+
11
+ ```
12
+ hello-service/
13
+ ├── src/
14
+ │ ├── app.js # Express application
15
+ │ ├── routes/
16
+ │ │ └── greetings.js # GET/POST endpoints
17
+ │ └── handlers/
18
+ │ └── greetings.js # Business logic
19
+ ├── package.json # Only Express and business dependencies
20
+ └── .env # PORT=3000
21
+ ```
22
+
23
+ ### 2. Installation Steps
24
+
25
+ #### Step 1: Add Service Wrapper Dependency
26
+
27
+ ```bash
28
+ cd hello-service
29
+ npm install @onlineapps/service-wrapper
30
+ ```
31
+
32
+ #### Step 2: Create Configuration Directory
33
+
34
+ ```bash
35
+ mkdir conn-config
36
+ ```
37
+
38
+ #### Step 3: Create Operations Schema
39
+
40
+ ```json
41
+ // conn-config/operations.json
42
+ {
43
+ "operations": {
44
+ "good-day": {
45
+ "description": "Generate good day greeting",
46
+ "endpoint": "/api/good-day",
47
+ "method": "POST",
48
+ "input": {
49
+ "name": { "type": "string", "required": true }
50
+ },
51
+ "output": {
52
+ "message": { "type": "string" },
53
+ "timestamp": { "type": "datetime" }
54
+ }
55
+ },
56
+ "good-bye": {
57
+ "description": "Generate goodbye message",
58
+ "endpoint": "/api/good-bye",
59
+ "method": "POST",
60
+ "input": {
61
+ "name": { "type": "string", "required": true }
62
+ },
63
+ "output": {
64
+ "message": { "type": "string" },
65
+ "timestamp": { "type": "datetime" }
66
+ }
67
+ }
68
+ }
69
+ }
70
+ ```
71
+
72
+ #### Step 4: Create Service Configuration
73
+
74
+ ```json
75
+ // conn-config/config.json
76
+ {
77
+ "service": {
78
+ "name": "hello-service",
79
+ "version": "1.0.0",
80
+ "port": 3000
81
+ },
82
+ "wrapper": {
83
+ "mq": {
84
+ "url": "${RABBITMQ_URL}",
85
+ "prefetch": 10
86
+ },
87
+ "monitoring": {
88
+ "enabled": true,
89
+ "metrics": ["requests", "errors", "duration"]
90
+ },
91
+ "health": {
92
+ "enabled": true,
93
+ "endpoint": "/health"
94
+ },
95
+ "registry": {
96
+ "enabled": true,
97
+ "url": "${REGISTRY_URL}",
98
+ "heartbeatInterval": 30000
99
+ }
100
+ }
101
+ }
102
+ ```
103
+
104
+ #### Step 5: Create Service Entry Point
105
+
106
+ ```javascript
107
+ // hello-service/index.js (NEW FILE)
108
+ const express = require('express');
109
+ const { ServiceWrapper } = require('@onlineapps/service-wrapper');
110
+
111
+ // Load Express application
112
+ const app = require('./src/app');
113
+
114
+ // Load configuration
115
+ const config = require('./conn-config/config.json');
116
+ const operations = require('./conn-config/operations.json');
117
+
118
+ // Start service
119
+ async function start() {
120
+ // 1. Start Express server
121
+ const port = process.env.PORT || config.service.port;
122
+ const server = app.listen(port, () => {
123
+ console.log(`${config.service.name} listening on port ${port}`);
124
+ });
125
+
126
+ // 2. Initialize Service Wrapper
127
+ const wrapper = new ServiceWrapper({
128
+ app,
129
+ server,
130
+ config,
131
+ operations
132
+ });
133
+
134
+ await wrapper.initialize();
135
+ console.log(`${config.service.name} ready with all infrastructure components`);
136
+
137
+ // 3. Graceful shutdown
138
+ process.on('SIGTERM', async () => {
139
+ console.log('SIGTERM received, shutting down gracefully...');
140
+ await wrapper.shutdown();
141
+ server.close(() => {
142
+ process.exit(0);
143
+ });
144
+ });
145
+ }
146
+
147
+ // Start
148
+ start().catch(error => {
149
+ console.error('Failed to start service:', error);
150
+ process.exit(1);
151
+ });
152
+ ```
153
+
154
+ #### Step 6: Update package.json
155
+
156
+ ```json
157
+ {
158
+ "name": "hello-service",
159
+ "version": "1.0.0",
160
+ "main": "index.js",
161
+ "scripts": {
162
+ "start": "node index.js",
163
+ "dev": "nodemon index.js",
164
+ "test": "jest"
165
+ },
166
+ "dependencies": {
167
+ "express": "^4.18.0",
168
+ "@onlineapps/service-wrapper": "^2.0.0"
169
+ },
170
+ "devDependencies": {
171
+ "nodemon": "^2.0.0",
172
+ "jest": "^29.0.0"
173
+ }
174
+ }
175
+ ```
176
+
177
+ ### 3. Final State - Service with Wrapper
178
+
179
+ ```
180
+ hello-service/
181
+ ├── src/
182
+ │ ├── app.js # Express app - UNCHANGED
183
+ │ ├── routes/ # Business endpoints - UNCHANGED
184
+ │ └── handlers/ # Business logic - UNCHANGED
185
+ ├── conn-config/ # NEW - wrapper configuration
186
+ │ ├── config.json # Service & wrapper config
187
+ │ └── operations.json # Operation to endpoint mapping
188
+ ├── index.js # NEW - main entry point
189
+ ├── package.json # + @onlineapps/service-wrapper
190
+ └── .env # RABBITMQ_URL, REGISTRY_URL, PORT
191
+ ```
192
+
193
+ ## Runtime Behavior
194
+
195
+ ### Startup Sequence
196
+
197
+ When running `npm start`:
198
+
199
+ 1. **Express Server Starts** on port 3000
200
+ 2. **ServiceWrapper Initializes Components:**
201
+ - MQConnector connects to RabbitMQ
202
+ - Subscribes to `workflow.init` queue
203
+ - Subscribes to `{service-name}.workflow` queue
204
+ - HealthConnector adds `/health` endpoint
205
+ - MonitoringConnector starts collecting metrics
206
+ - RegistryConnector registers service
207
+ 3. **Service is Ready** - accepts both HTTP and MQ requests
208
+
209
+ ### Request Processing
210
+
211
+ #### HTTP Request Flow
212
+ ```
213
+ Client → HTTP → Express Router → Handler → Response
214
+
215
+ MonitoringConnector (metrics)
216
+ ```
217
+
218
+ #### MQ Message Flow
219
+ ```
220
+ RabbitMQ → MQConnector → Parse operations.json → HTTP call localhost:3000/api/endpoint
221
+
222
+ Express Router → Handler
223
+
224
+ Response → MQ
225
+ ```
226
+
227
+ ## What Service DOESN'T Need to Handle
228
+
229
+ - ❌ RabbitMQ connection management
230
+ - ❌ Queue subscription logic
231
+ - ❌ Message parsing and validation
232
+ - ❌ Service discovery registration
233
+ - ❌ Health check implementation
234
+ - ❌ Monitoring middleware
235
+ - ❌ Retry and error handling
236
+
237
+ **All handled by Service Wrapper!**
238
+
239
+ ## Environment Variables
240
+
241
+ ```bash
242
+ # .env
243
+ PORT=3000
244
+ RABBITMQ_URL=amqp://rabbit:5672
245
+ REGISTRY_URL=http://registry:4000
246
+ REDIS_HOST=redis:6379
247
+ ```
248
+
249
+ ## Benefits of This Approach
250
+
251
+ 1. **Zero Infrastructure Code in Service** - Only business logic
252
+ 2. **Central Management** - Update wrapper version for all services
253
+ 3. **Single Process** - Simple deployment and debugging
254
+ 4. **Full Functionality** - Service maintains all capabilities
255
+ 5. **Minimal Changes** - Existing services need minimal modification
256
+
257
+ ## Migration from Existing Service
258
+
259
+ For services already in production:
260
+
261
+ 1. Keep all existing code unchanged
262
+ 2. Add conn-config directory with operations.json
263
+ 3. Add index.js entry point
264
+ 4. Add Service Wrapper dependency
265
+ 5. Deploy - no breaking changes!
266
+
267
+ ## Testing with Service Wrapper
268
+
269
+ Services can be tested in two modes:
270
+
271
+ ### 1. Without Wrapper (Unit Tests)
272
+ ```javascript
273
+ // Direct Express app testing
274
+ const app = require('./src/app');
275
+ const request = require('supertest');
276
+
277
+ test('GET /api/good-day', async () => {
278
+ const res = await request(app)
279
+ .post('/api/good-day')
280
+ .send({ name: 'World' });
281
+ expect(res.status).toBe(200);
282
+ });
283
+ ```
284
+
285
+ ### 2. With Wrapper (Integration Tests)
286
+ ```javascript
287
+ // Full service testing with infrastructure
288
+ const { start } = require('./index');
289
+
290
+ beforeAll(async () => {
291
+ await start();
292
+ });
293
+
294
+ test('Service registered', async () => {
295
+ // Test registry registration
296
+ // Test MQ handling
297
+ // Test health endpoint
298
+ });
299
+ ```
300
+
301
+ ## Common Patterns
302
+
303
+ ### Database Connection
304
+ ```javascript
305
+ // Service maintains its own DB connection
306
+ const mongoose = require('mongoose');
307
+
308
+ async function start() {
309
+ // 1. Connect to database
310
+ await mongoose.connect(process.env.MONGODB_URL);
311
+
312
+ // 2. Start Express
313
+ const server = app.listen(port);
314
+
315
+ // 3. Initialize wrapper
316
+ const wrapper = new ServiceWrapper({ app, server, config, operations });
317
+ await wrapper.initialize();
318
+ }
319
+ ```
320
+
321
+ ### Custom Health Checks
322
+ ```javascript
323
+ // Service can provide custom health check logic
324
+ wrapper.onHealthCheck(async () => {
325
+ return {
326
+ database: mongoose.connection.readyState === 1,
327
+ customCheck: await myCustomCheck()
328
+ };
329
+ });
330
+ ```
331
+
332
+ ### Custom Metrics
333
+ ```javascript
334
+ // Service can add custom metrics
335
+ wrapper.monitoring.recordCustomMetric('orders_processed', orderCount);
336
+ ```
337
+
338
+ ## Troubleshooting
339
+
340
+ ### Service doesn't receive MQ messages
341
+ - Check operations.json mapping
342
+ - Verify queue names in RabbitMQ
343
+ - Check RABBITMQ_URL environment variable
344
+
345
+ ### Health check fails
346
+ - Verify all wrapper components initialized
347
+ - Check custom health check logic
348
+ - Review logs for initialization errors
349
+
350
+ ### Registry not updating
351
+ - Check REGISTRY_URL environment variable
352
+ - Verify network connectivity
353
+ - Check heartbeat interval configuration
@@ -360,4 +360,46 @@ Each extension follows the same pattern:
360
360
  1. Define operation in operations.json
361
361
  2. Specify type in `external` block
362
362
  3. Map inputs/outputs
363
- 4. Service Wrapper handles execution
363
+ 4. Service Wrapper handles execution
364
+
365
+ ## Legacy Service Support
366
+
367
+ ### Adapter Pattern for Existing Services
368
+
369
+ For services that cannot be immediately refactored:
370
+
371
+ ```json
372
+ {
373
+ "operations": {
374
+ "legacy-operation": {
375
+ "description": "Wrapper for legacy endpoint",
376
+ "adapter": {
377
+ "type": "http-proxy",
378
+ "target": "http://legacy-service:3000",
379
+ "endpoint": "/api/v1/operation",
380
+ "method": "POST",
381
+ "transform": {
382
+ "request": "$.input -> legacy format",
383
+ "response": "legacy format -> $.output"
384
+ }
385
+ }
386
+ }
387
+ }
388
+ }
389
+ ```
390
+
391
+ ### External Handler Adapters
392
+
393
+ Create wrapper handlers outside the legacy service:
394
+
395
+ ```
396
+ /services/
397
+ /legacy-service/ # Original service - NO CHANGES
398
+ /legacy-service-wrapper/ # Adapter layer
399
+ /conn-config/
400
+ operations.json # Operations mapping
401
+ /handlers/
402
+ index.js # Handlers calling HTTP
403
+ ```
404
+
405
+ This allows gradual migration without touching legacy code.