@onlineapps/service-wrapper 2.0.8 → 2.0.9
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.
- package/README.md +66 -39
- package/docs/ARCHITECTURE_DECISION.md +200 -0
- package/docs/FINAL_ARCHITECTURE.md +271 -0
- package/docs/HANDLER_VS_HTTP_COMPARISON.md +269 -0
- package/docs/INSTALLATION_GUIDE.md +353 -0
- package/docs/OPERATIONS_SCHEMA.md +43 -1
- package/docs/WRAPPER_ARCHITECTURE.md +218 -0
- package/onlineapps-service-wrapper-2.0.8.tgz +0 -0
- package/package.json +3 -3
- package/src/ServiceWrapper.js +432 -273
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
# Service Wrapper Architecture
|
|
2
|
+
|
|
3
|
+
> **NOTE: This document describes initial architecture concepts. For the production-ready decision, see [FINAL_ARCHITECTURE.md](./FINAL_ARCHITECTURE.md)**
|
|
4
|
+
|
|
5
|
+
## Definition
|
|
6
|
+
|
|
7
|
+
Service Wrapper is a **collection of connectors** that provides all components necessary for a business service to function within the system.
|
|
8
|
+
|
|
9
|
+
## Core Principles
|
|
10
|
+
|
|
11
|
+
1. **Component Collection** - Wrapper is NOT a framework but a set of reusable components
|
|
12
|
+
2. **Central Management** - All services use the same wrapper version for consistency
|
|
13
|
+
3. **Version Independence** - Each service can pin its wrapper version as needed
|
|
14
|
+
4. **Duplicate by Design** - Each service has its own wrapper instance (not shared)
|
|
15
|
+
|
|
16
|
+
## Architecture Pattern: Enhanced Service
|
|
17
|
+
|
|
18
|
+
```javascript
|
|
19
|
+
// Business service enhanced with wrapper components
|
|
20
|
+
const express = require('express');
|
|
21
|
+
const { MQConnector, MonitoringConnector, HealthConnector } = require('@onlineapps/service-wrapper');
|
|
22
|
+
|
|
23
|
+
class EnhancedService {
|
|
24
|
+
constructor() {
|
|
25
|
+
// Core business service
|
|
26
|
+
this.app = express();
|
|
27
|
+
this.setupBusinessRoutes();
|
|
28
|
+
|
|
29
|
+
// Wrapper components
|
|
30
|
+
this.mq = new MQConnector(this);
|
|
31
|
+
this.monitoring = new MonitoringConnector(this);
|
|
32
|
+
this.health = new HealthConnector(this);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async start() {
|
|
36
|
+
// 1. Start HTTP server
|
|
37
|
+
await this.app.listen(this.config.port);
|
|
38
|
+
|
|
39
|
+
// 2. Connect to MQ
|
|
40
|
+
await this.mq.connect();
|
|
41
|
+
await this.mq.consume('workflow.init', this.handleWorkflow.bind(this));
|
|
42
|
+
await this.mq.consume(`${this.config.name}.workflow`, this.handleServiceMessage.bind(this));
|
|
43
|
+
|
|
44
|
+
// 3. Start monitoring
|
|
45
|
+
await this.monitoring.start();
|
|
46
|
+
|
|
47
|
+
// 4. Register health checks
|
|
48
|
+
this.health.register('/health', this.checkHealth.bind(this));
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
handleWorkflow(message) {
|
|
52
|
+
// Wrapper handles workflow routing
|
|
53
|
+
const operation = this.config.operations[message.step.operation];
|
|
54
|
+
|
|
55
|
+
// Call own HTTP endpoint
|
|
56
|
+
return this.callHttp(operation.endpoint, message.input);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
callHttp(endpoint, data) {
|
|
60
|
+
// Internal HTTP call to business logic
|
|
61
|
+
return fetch(`http://localhost:${this.config.port}${endpoint}`, {
|
|
62
|
+
method: 'POST',
|
|
63
|
+
body: JSON.stringify(data)
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Component Responsibilities
|
|
70
|
+
|
|
71
|
+
### MQ Connector
|
|
72
|
+
- Listen on `workflow.init` queue
|
|
73
|
+
- Listen on service-specific queues
|
|
74
|
+
- Route messages between services
|
|
75
|
+
- Handle dead letter queues
|
|
76
|
+
|
|
77
|
+
### Monitoring Connector
|
|
78
|
+
- Collect metrics
|
|
79
|
+
- Export to monitoring system
|
|
80
|
+
- Track request/response times
|
|
81
|
+
- Monitor queue depth
|
|
82
|
+
|
|
83
|
+
### Health Connector
|
|
84
|
+
- Provide `/health` endpoint
|
|
85
|
+
- Check service dependencies
|
|
86
|
+
- Report readiness status
|
|
87
|
+
- Aggregate component health
|
|
88
|
+
|
|
89
|
+
### Registry Connector
|
|
90
|
+
- Register service on startup
|
|
91
|
+
- Send heartbeat
|
|
92
|
+
- Update capabilities
|
|
93
|
+
- Handle deregistration
|
|
94
|
+
|
|
95
|
+
## Single Process Architecture
|
|
96
|
+
|
|
97
|
+
**Decision:** Use single process with embedded wrapper components.
|
|
98
|
+
|
|
99
|
+
### Rationale:
|
|
100
|
+
1. **Simplicity** - One deployment unit
|
|
101
|
+
2. **Efficiency** - No IPC overhead
|
|
102
|
+
3. **Atomicity** - Components share state
|
|
103
|
+
4. **Debugging** - Single log stream
|
|
104
|
+
|
|
105
|
+
### Implementation:
|
|
106
|
+
```javascript
|
|
107
|
+
// service/index.js
|
|
108
|
+
const ServiceWrapper = require('@onlineapps/service-wrapper');
|
|
109
|
+
const app = require('./src/app'); // Express app
|
|
110
|
+
const config = require('./conn-config/config.json');
|
|
111
|
+
const operations = require('./conn-config/operations.json');
|
|
112
|
+
|
|
113
|
+
// Single process startup
|
|
114
|
+
async function start() {
|
|
115
|
+
// Business service
|
|
116
|
+
const server = app.listen(config.port);
|
|
117
|
+
|
|
118
|
+
// Wrapper components
|
|
119
|
+
const wrapper = new ServiceWrapper({
|
|
120
|
+
app,
|
|
121
|
+
server,
|
|
122
|
+
config,
|
|
123
|
+
operations
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
await wrapper.initialize();
|
|
127
|
+
console.log(`Service ${config.name} running with wrapper components`);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
start().catch(console.error);
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Configuration Pattern
|
|
134
|
+
|
|
135
|
+
### operations.json
|
|
136
|
+
```json
|
|
137
|
+
{
|
|
138
|
+
"operations": {
|
|
139
|
+
"operation-name": {
|
|
140
|
+
"endpoint": "/api/operation",
|
|
141
|
+
"method": "POST",
|
|
142
|
+
"input": { "schema": "..." },
|
|
143
|
+
"output": { "schema": "..." }
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### config.json
|
|
150
|
+
```json
|
|
151
|
+
{
|
|
152
|
+
"service": {
|
|
153
|
+
"name": "my-service",
|
|
154
|
+
"port": 3000
|
|
155
|
+
},
|
|
156
|
+
"wrapper": {
|
|
157
|
+
"mq": {
|
|
158
|
+
"url": "${RABBITMQ_URL}"
|
|
159
|
+
},
|
|
160
|
+
"monitoring": {
|
|
161
|
+
"enabled": true
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## Health Check Strategy
|
|
168
|
+
|
|
169
|
+
Health checks are **provided by wrapper** but **implemented by service**:
|
|
170
|
+
|
|
171
|
+
```javascript
|
|
172
|
+
// Wrapper provides endpoint
|
|
173
|
+
app.get('/health', healthConnector.handler);
|
|
174
|
+
|
|
175
|
+
// Service implements check
|
|
176
|
+
class MyService {
|
|
177
|
+
checkHealth() {
|
|
178
|
+
return {
|
|
179
|
+
status: this.isHealthy() ? 'healthy' : 'unhealthy',
|
|
180
|
+
database: this.db.isConnected(),
|
|
181
|
+
dependencies: this.checkDependencies()
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## Migration Path
|
|
188
|
+
|
|
189
|
+
### From Standalone Service:
|
|
190
|
+
1. Add `@onlineapps/service-wrapper` dependency
|
|
191
|
+
2. Create `conn-config/operations.json`
|
|
192
|
+
3. Wrap service startup with ServiceWrapper
|
|
193
|
+
4. Remove duplicate infrastructure code
|
|
194
|
+
|
|
195
|
+
### From Two-Process Architecture:
|
|
196
|
+
1. Merge wrapper.js into service index.js
|
|
197
|
+
2. Remove separate wrapper process
|
|
198
|
+
3. Consolidate configuration
|
|
199
|
+
4. Single deployment unit
|
|
200
|
+
|
|
201
|
+
## Benefits
|
|
202
|
+
|
|
203
|
+
1. **No Duplication** - Common components in wrapper
|
|
204
|
+
2. **Central Updates** - Update wrapper version for all services
|
|
205
|
+
3. **Consistent Behavior** - All services work the same way
|
|
206
|
+
4. **Simple Deployment** - One process per service
|
|
207
|
+
5. **Clear Separation** - Business logic vs infrastructure
|
|
208
|
+
|
|
209
|
+
## Drawbacks
|
|
210
|
+
|
|
211
|
+
1. **Tight Coupling** - Service depends on wrapper version
|
|
212
|
+
2. **Restart Required** - Any change restarts everything
|
|
213
|
+
3. **Mixed Dependencies** - Business and infrastructure together
|
|
214
|
+
4. **Testing Complexity** - Must mock wrapper components
|
|
215
|
+
|
|
216
|
+
## Conclusion
|
|
217
|
+
|
|
218
|
+
Service Wrapper as a **component collection** in a **single process** provides the best balance of simplicity, efficiency, and maintainability for our microservices architecture.
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onlineapps/service-wrapper",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.9",
|
|
4
4
|
"description": "Thin orchestration layer for microservices - delegates all infrastructure concerns to specialized connectors",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -25,14 +25,14 @@
|
|
|
25
25
|
"license": "MIT",
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"@onlineapps/conn-base-cache": "^1.0.0",
|
|
28
|
-
"@onlineapps/conn-base-monitoring": "
|
|
28
|
+
"@onlineapps/conn-base-monitoring": "^1.0.0",
|
|
29
29
|
"@onlineapps/conn-infra-error-handler": "^1.0.0",
|
|
30
30
|
"@onlineapps/conn-infra-mq": "^1.1.0",
|
|
31
31
|
"@onlineapps/conn-orch-api-mapper": "^1.0.0",
|
|
32
32
|
"@onlineapps/conn-orch-cookbook": "^2.0.0",
|
|
33
33
|
"@onlineapps/conn-orch-orchestrator": "^1.0.1",
|
|
34
34
|
"@onlineapps/conn-orch-registry": "^1.1.4",
|
|
35
|
-
"@onlineapps/monitoring-core": "
|
|
35
|
+
"@onlineapps/monitoring-core": "^1.0.0"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
38
|
"express": "^5.1.0",
|