@adaas/a-utils 0.1.17 ā 0.1.19
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/dist/index.d.mts +964 -354
- package/dist/index.d.ts +964 -354
- package/dist/index.js +1426 -714
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1426 -714
- package/dist/index.mjs.map +1 -1
- package/examples/A-Channel-examples.ts +13 -11
- package/examples/A-Command-examples-2.ts +429 -0
- package/examples/A-Command-examples.ts +487 -202
- package/examples/A-StateMachine-examples.ts +609 -0
- package/package.json +3 -2
- package/src/index.ts +1 -2
- package/src/lib/A-Channel/A-Channel.component.ts +14 -74
- package/src/lib/A-Channel/A-Channel.error.ts +5 -5
- package/src/lib/A-Channel/A-Channel.types.ts +2 -10
- package/src/lib/A-Channel/A-ChannelRequest.context.ts +25 -74
- package/src/lib/A-Command/A-Command.constants.ts +78 -23
- package/src/lib/A-Command/A-Command.entity.ts +447 -119
- package/src/lib/A-Command/A-Command.error.ts +11 -0
- package/src/lib/A-Command/A-Command.types.ts +96 -20
- package/src/lib/A-Command/A-CommandExecution.context.ts +0 -0
- package/src/lib/A-Command/README.md +164 -68
- package/src/lib/A-Config/A-Config.container.ts +2 -2
- package/src/lib/A-Config/A-Config.context.ts +19 -5
- package/src/lib/A-Config/components/ConfigReader.component.ts +1 -1
- package/src/lib/A-Logger/A-Logger.component.ts +211 -35
- package/src/lib/A-Logger/A-Logger.constants.ts +50 -10
- package/src/lib/A-Logger/A-Logger.env.ts +17 -1
- package/src/lib/A-Memory/A-Memory.component.ts +440 -0
- package/src/lib/A-Memory/A-Memory.constants.ts +49 -0
- package/src/lib/A-Memory/A-Memory.context.ts +14 -118
- package/src/lib/A-Memory/A-Memory.error.ts +21 -0
- package/src/lib/A-Memory/A-Memory.types.ts +21 -0
- package/src/lib/A-Operation/A-Operation.context.ts +58 -0
- package/src/lib/A-Operation/A-Operation.types.ts +47 -0
- package/src/lib/A-StateMachine/A-StateMachine.component.ts +258 -0
- package/src/lib/A-StateMachine/A-StateMachine.constants.ts +18 -0
- package/src/lib/A-StateMachine/A-StateMachine.error.ts +10 -0
- package/src/lib/A-StateMachine/A-StateMachine.types.ts +20 -0
- package/src/lib/A-StateMachine/A-StateMachineTransition.context.ts +41 -0
- package/src/lib/A-StateMachine/README.md +391 -0
- package/tests/A-Channel.test.ts +17 -14
- package/tests/A-Command.test.ts +548 -460
- package/tests/A-Logger.test.ts +8 -4
- package/tests/A-Memory.test.ts +151 -115
- package/tests/A-Schedule.test.ts +2 -2
- package/tests/A-StateMachine.test.ts +760 -0
|
@@ -1,270 +1,555 @@
|
|
|
1
|
+
|
|
1
2
|
/**
|
|
2
|
-
* A-Command
|
|
3
|
+
* A-Command Multi-Service Processing Example
|
|
4
|
+
*
|
|
5
|
+
* This example demonstrates the core concepts of A-Command:
|
|
6
|
+
*
|
|
7
|
+
* 1. **Multi-Service Processing**: Commands can be executed across different services
|
|
8
|
+
* 2. **Serialization**: Commands can be serialized and transmitted between services
|
|
9
|
+
* 3. **Component-Based Behavior**: Different components can extend command behavior
|
|
10
|
+
* 4. **Dependency Injection**: Commands use DI for accessing services and resources
|
|
11
|
+
* 5. **Lifecycle Management**: Commands follow a structured execution lifecycle
|
|
3
12
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
13
|
+
* The example shows:
|
|
14
|
+
* - Service A starts command execution and delegates to Service B
|
|
15
|
+
* - Service B processes the command with access to shared memory
|
|
16
|
+
* - A simple channel routes commands between services
|
|
17
|
+
* - Each service has its own component extending command behavior
|
|
6
18
|
*/
|
|
7
19
|
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
20
|
+
import { A_Caller, A_Component, A_Concept, A_Container, A_Error, A_Feature, A_FormatterHelper, A_Inject } from "@adaas/a-concept"
|
|
21
|
+
import { A_ChannelRequest } from "@adaas/a-utils/lib/A-Channel/A-ChannelRequest.context";
|
|
22
|
+
import { A_MemoryContext } from "@adaas/a-utils/lib/A-Memory/A-Memory.context";
|
|
23
|
+
import { A_OperationContext } from "@adaas/a-utils/lib/A-Operation/A-Operation.context";
|
|
24
|
+
import { A_StateMachine } from "@adaas/a-utils/lib/A-StateMachine/A-StateMachine.component";
|
|
25
|
+
import { A_Channel, A_Command, A_Command_Status, A_CommandFeatures, A_Logger, A_Memory, A_TYPES__Command_Serialized } from "src"
|
|
12
26
|
|
|
13
|
-
// Example 1: Basic Command Usage
|
|
14
|
-
async function basicCommandExample() {
|
|
15
|
-
console.log('\n=== Basic Command Example ===');
|
|
16
|
-
|
|
17
|
-
const command = new A_Command({
|
|
18
|
-
action: 'greet',
|
|
19
|
-
name: 'World'
|
|
20
|
-
});
|
|
21
27
|
|
|
22
|
-
|
|
28
|
+
// ============================================================================
|
|
29
|
+
// ====================== Command Definition =================================
|
|
30
|
+
// ============================================================================
|
|
23
31
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
32
|
+
/**
|
|
33
|
+
* Command parameter type definition
|
|
34
|
+
* Defines the input data structure required to execute the command
|
|
35
|
+
*/
|
|
36
|
+
type myCommandParams = { userId: string };
|
|
27
37
|
|
|
28
|
-
|
|
38
|
+
/**
|
|
39
|
+
* Command result type definition
|
|
40
|
+
* Defines the output data structure produced by successful execution
|
|
41
|
+
*/
|
|
42
|
+
type myCommandResult = { success: boolean };
|
|
29
43
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
44
|
+
/**
|
|
45
|
+
* Custom Command Implementation
|
|
46
|
+
*
|
|
47
|
+
* This command demonstrates:
|
|
48
|
+
* - Type-safe parameter and result definitions
|
|
49
|
+
* - Custom properties for storing runtime data
|
|
50
|
+
* - Custom serialization extending the base toJSON method
|
|
51
|
+
* - Cross-service data transmission capabilities
|
|
52
|
+
*/
|
|
53
|
+
class myCommand extends A_Command<myCommandParams, myCommandResult> {
|
|
54
|
+
|
|
55
|
+
/** Runtime property to store user data fetched during execution */
|
|
56
|
+
user?: { id: string };
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Custom serialization method
|
|
60
|
+
*
|
|
61
|
+
* Extends the base toJSON to include additional properties
|
|
62
|
+
* for cross-service transmission. This allows other services
|
|
63
|
+
* to receive not just the standard command data but also
|
|
64
|
+
* custom fields relevant to the business logic.
|
|
65
|
+
*/
|
|
66
|
+
toJSON(): A_TYPES__Command_Serialized<myCommandParams, myCommandResult> & { userId: string } {
|
|
67
|
+
return {
|
|
68
|
+
...super.toJSON(),
|
|
69
|
+
userId: this.params.userId,
|
|
70
|
+
}
|
|
71
|
+
}
|
|
33
72
|
}
|
|
34
73
|
|
|
35
|
-
// Example 2: Typed Command with Custom Logic
|
|
36
|
-
interface UserCreateParams {
|
|
37
|
-
name: string;
|
|
38
|
-
email: string;
|
|
39
|
-
role: 'admin' | 'user';
|
|
40
|
-
}
|
|
41
74
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
profileCreated: boolean;
|
|
46
|
-
}
|
|
75
|
+
// ============================================================================
|
|
76
|
+
// ====================== Service A Component ===============================
|
|
77
|
+
// ============================================================================
|
|
47
78
|
|
|
48
|
-
|
|
79
|
+
/**
|
|
80
|
+
* Service A Command Processor
|
|
81
|
+
*
|
|
82
|
+
* This component extends the command lifecycle in Service A by implementing
|
|
83
|
+
* custom behavior at different execution phases. It demonstrates:
|
|
84
|
+
*
|
|
85
|
+
* - Pre-execution setup (storing data in shared memory)
|
|
86
|
+
* - Main execution logic (delegating to Service B via channel)
|
|
87
|
+
* - Post-execution cleanup and logging
|
|
88
|
+
* - Inter-service communication patterns
|
|
89
|
+
*/
|
|
90
|
+
class ServiceA_MyCommandProcessor extends A_Component {
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Pre-execution phase handler
|
|
94
|
+
*
|
|
95
|
+
* Runs before the main command execution begins.
|
|
96
|
+
* Used for:
|
|
97
|
+
* - Initial setup and preparation
|
|
98
|
+
* - Storing data in shared memory for other services
|
|
99
|
+
* - Validation and pre-processing
|
|
100
|
+
*
|
|
101
|
+
* @param command - The command instance being executed
|
|
102
|
+
* @param memory - Shared memory for cross-service data storage
|
|
103
|
+
* @param logger - Logger instance for tracking execution
|
|
104
|
+
*/
|
|
105
|
+
@A_Feature.Extend()
|
|
106
|
+
async [A_CommandFeatures.onBeforeExecute](
|
|
107
|
+
@A_Inject(A_Caller) command: myCommand,
|
|
108
|
+
@A_Inject(A_Memory) memory: A_Memory<{ user: { id: string } }>,
|
|
109
|
+
@A_Inject(A_Logger) logger: A_Logger,
|
|
110
|
+
) {
|
|
111
|
+
logger.info('Starting command execution in Service A');
|
|
49
112
|
|
|
50
|
-
|
|
113
|
+
// Store user data in shared memory for Service B to access
|
|
114
|
+
await memory.set('user', { id: '555' });
|
|
115
|
+
}
|
|
51
116
|
|
|
52
|
-
|
|
117
|
+
/**
|
|
118
|
+
* Main execution phase handler
|
|
119
|
+
*
|
|
120
|
+
* Contains the core business logic for Service A.
|
|
121
|
+
* In this example, it delegates processing to Service B
|
|
122
|
+
* by sending the serialized command through a channel.
|
|
123
|
+
*
|
|
124
|
+
* @param command - The command instance being executed
|
|
125
|
+
* @param channel - Communication channel for inter-service requests
|
|
126
|
+
* @param logger - Logger instance for tracking execution
|
|
127
|
+
*/
|
|
128
|
+
@A_Feature.Extend()
|
|
53
129
|
async [A_CommandFeatures.onExecute](
|
|
54
|
-
@A_Inject(
|
|
130
|
+
@A_Inject(A_Caller) command: myCommand,
|
|
131
|
+
@A_Inject(A_Channel) channel: A_Channel,
|
|
132
|
+
@A_Inject(A_Logger) logger: A_Logger,
|
|
55
133
|
) {
|
|
56
|
-
const command = A_Context.scope(this).resolve(CreateUserCommand)!;
|
|
57
|
-
const { name, email, role } = command.params;
|
|
58
134
|
|
|
59
|
-
console.log(`Creating user: ${name} (${email}) with role: ${role}`);
|
|
60
135
|
|
|
61
|
-
//
|
|
62
|
-
const
|
|
63
|
-
|
|
136
|
+
// Serialize command and send to Service B for processing
|
|
137
|
+
const response = await channel.request<any, A_TYPES__Command_Serialized<myCommandParams, myCommandResult>>({
|
|
138
|
+
container: 'ServiceB',
|
|
139
|
+
command: command.toJSON()
|
|
140
|
+
});
|
|
64
141
|
|
|
65
|
-
|
|
66
|
-
await memory.set('userId', userId);
|
|
67
|
-
await memory.set('createdAt', createdAt);
|
|
68
|
-
await memory.set('profileCreated', true);
|
|
142
|
+
command.fromJSON(response.data!);
|
|
69
143
|
|
|
70
|
-
console.log(`User created with ID: ${userId}`);
|
|
71
144
|
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
async function typedCommandExample() {
|
|
75
|
-
console.log('\n=== Typed Command with Custom Logic Example ===');
|
|
76
|
-
|
|
77
|
-
A_Context.reset();
|
|
78
|
-
A_Context.root.register(UserCreationService);
|
|
79
|
-
|
|
80
|
-
const command = new CreateUserCommand({
|
|
81
|
-
name: 'John Doe',
|
|
82
|
-
email: 'john@example.com',
|
|
83
|
-
role: 'user'
|
|
84
|
-
});
|
|
85
145
|
|
|
86
|
-
|
|
87
|
-
|
|
146
|
+
/**
|
|
147
|
+
* Post-execution phase handler
|
|
148
|
+
*
|
|
149
|
+
* Runs after the main execution completes (success or failure).
|
|
150
|
+
* Used for:
|
|
151
|
+
* - Cleanup operations
|
|
152
|
+
* - Final logging and metrics
|
|
153
|
+
* - Notification sending
|
|
154
|
+
*
|
|
155
|
+
* @param command - The command instance that was executed
|
|
156
|
+
* @param logger - Logger instance for tracking execution
|
|
157
|
+
*/
|
|
158
|
+
@A_Feature.Extend()
|
|
159
|
+
async [A_CommandFeatures.onAfterExecute](
|
|
160
|
+
@A_Inject(A_Caller) command: myCommand,
|
|
161
|
+
@A_Inject(A_Logger) logger: A_Logger,
|
|
162
|
+
) {
|
|
163
|
+
logger.info('Finishing command execution in Service A');
|
|
88
164
|
|
|
89
|
-
|
|
165
|
+
}
|
|
90
166
|
}
|
|
91
167
|
|
|
92
|
-
// Example 3: Command Serialization and Persistence
|
|
93
|
-
async function serializationExample() {
|
|
94
|
-
console.log('\n=== Command Serialization Example ===');
|
|
95
|
-
|
|
96
|
-
A_Context.reset();
|
|
97
|
-
A_Context.root.register(UserCreationService);
|
|
98
|
-
|
|
99
|
-
// Create and execute original command
|
|
100
|
-
const originalCommand = new CreateUserCommand({
|
|
101
|
-
name: 'Jane Smith',
|
|
102
|
-
email: 'jane@example.com',
|
|
103
|
-
role: 'admin'
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
A_Context.root.register(originalCommand);
|
|
107
|
-
await originalCommand.execute();
|
|
108
|
-
|
|
109
|
-
// Serialize command
|
|
110
|
-
const serialized = originalCommand.toJSON();
|
|
111
|
-
console.log('Command serialized for storage/transmission');
|
|
112
168
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
169
|
+
// ============================================================================
|
|
170
|
+
// ====================== Service B Component ===============================
|
|
171
|
+
// ============================================================================
|
|
116
172
|
|
|
117
|
-
|
|
118
|
-
|
|
173
|
+
/**
|
|
174
|
+
* Service B Command Processor
|
|
175
|
+
*
|
|
176
|
+
* This component handles command processing in Service B after receiving
|
|
177
|
+
* the command from Service A. It demonstrates:
|
|
178
|
+
*
|
|
179
|
+
* - Accessing shared memory data from other services
|
|
180
|
+
* - Processing commands with context from previous services
|
|
181
|
+
* - Stateful command execution across service boundaries
|
|
182
|
+
*/
|
|
183
|
+
class ServiceB_MyCommandProcessor extends A_Component {
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Pre-execution setup in Service B
|
|
187
|
+
*
|
|
188
|
+
* Retrieves data from shared memory that was stored by Service A
|
|
189
|
+
* and populates the command with additional context needed for processing.
|
|
190
|
+
*
|
|
191
|
+
* This shows how commands can accumulate state and data as they
|
|
192
|
+
* move through different services in a distributed system.
|
|
193
|
+
*
|
|
194
|
+
* @param command - The command instance being executed
|
|
195
|
+
* @param memory - Shared memory for accessing cross-service data
|
|
196
|
+
* @param logger - Logger instance for tracking execution
|
|
197
|
+
*/
|
|
198
|
+
@A_Feature.Extend()
|
|
199
|
+
async [A_CommandFeatures.onBeforeExecute](
|
|
200
|
+
@A_Inject(A_Caller) command: myCommand,
|
|
201
|
+
@A_Inject(A_Memory) memory: A_Memory<{ user: { id: string } }>,
|
|
202
|
+
@A_Inject(A_Logger) logger: A_Logger,
|
|
203
|
+
) {
|
|
204
|
+
logger.info('Starting command execution in Service B');
|
|
119
205
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
console.log(`- Duration: ${restoredCommand.duration}ms`);
|
|
123
|
-
console.log(`- User ID: ${restoredCommand.result?.userId}`);
|
|
124
|
-
console.log(`- Created At: ${restoredCommand.result?.createdAt}`);
|
|
125
|
-
}
|
|
206
|
+
// Retrieve user data that was stored by Service A
|
|
207
|
+
const user = await memory.get('user');
|
|
126
208
|
|
|
127
|
-
|
|
128
|
-
class FailingCommand extends A_Command<{ shouldFail: boolean }, { success: boolean }> { }
|
|
209
|
+
logger.info('Retrieved user from memory:', user);
|
|
129
210
|
|
|
130
|
-
|
|
211
|
+
// Populate command with additional context
|
|
212
|
+
command.user = user;
|
|
213
|
+
// throw new Error('Simulated error in Service B');
|
|
214
|
+
}
|
|
131
215
|
|
|
132
|
-
|
|
216
|
+
/**
|
|
217
|
+
* Main execution logic in Service B
|
|
218
|
+
*
|
|
219
|
+
* Handles the actual business logic processing for this command
|
|
220
|
+
* in Service B. This is where the final processing occurs after
|
|
221
|
+
* the command has been prepared by Service A.
|
|
222
|
+
*
|
|
223
|
+
* @param command - The command instance being executed
|
|
224
|
+
* @param logger - Logger instance for tracking execution
|
|
225
|
+
*/
|
|
226
|
+
@A_Feature.Extend()
|
|
133
227
|
async [A_CommandFeatures.onExecute](
|
|
134
|
-
@A_Inject(
|
|
228
|
+
@A_Inject(A_Caller) command: myCommand,
|
|
229
|
+
@A_Inject(A_Logger) logger: A_Logger,
|
|
135
230
|
) {
|
|
136
|
-
|
|
231
|
+
logger.info('Executing command in Service B', command.status);
|
|
137
232
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
}));
|
|
233
|
+
// Perform the actual business logic processing
|
|
234
|
+
// In a real scenario, this might involve:
|
|
235
|
+
// - Database operations
|
|
236
|
+
// - External API calls
|
|
237
|
+
// - Complex business logic calculations
|
|
238
|
+
// - Result generation
|
|
145
239
|
|
|
146
|
-
|
|
147
|
-
|
|
240
|
+
// For this example, we'll just set a success result
|
|
241
|
+
// Uncomment the next line to see result handling:
|
|
242
|
+
// command.result = { success: true };
|
|
243
|
+
// await command.complete({success: true});
|
|
244
|
+
|
|
245
|
+
throw new Error('Simulated error in Service B');
|
|
148
246
|
|
|
149
|
-
await memory.set('success', true);
|
|
150
247
|
}
|
|
151
248
|
}
|
|
152
249
|
|
|
153
|
-
async function errorHandlingExample() {
|
|
154
|
-
console.log('\n=== Error Handling Example ===');
|
|
155
250
|
|
|
156
|
-
|
|
157
|
-
|
|
251
|
+
// ============================================================================
|
|
252
|
+
// ====================== Inter-Service Communication ========================
|
|
253
|
+
// ============================================================================
|
|
158
254
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
255
|
+
/**
|
|
256
|
+
* Simple Channel Implementation
|
|
257
|
+
*
|
|
258
|
+
* A basic channel for routing commands between different services/containers.
|
|
259
|
+
* This demonstrates:
|
|
260
|
+
*
|
|
261
|
+
* - Command routing based on container names
|
|
262
|
+
* - Command deserialization and reconstruction in target service
|
|
263
|
+
* - Command execution in the target service context
|
|
264
|
+
* - Result serialization and response handling
|
|
265
|
+
*
|
|
266
|
+
* In production, this might be replaced with more sophisticated
|
|
267
|
+
* message queues, HTTP APIs, or service mesh communications.
|
|
268
|
+
*/
|
|
269
|
+
class SimpleChannel extends A_Channel {
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Handle incoming command routing requests
|
|
273
|
+
*
|
|
274
|
+
* This method:
|
|
275
|
+
* 1. Finds the target container by name
|
|
276
|
+
* 2. Resolves the command constructor in the target scope
|
|
277
|
+
* 3. Reconstructs the command from serialized data
|
|
278
|
+
* 4. Executes the command in the target service
|
|
279
|
+
* 5. Returns the serialized result
|
|
280
|
+
*
|
|
281
|
+
* @param memory - Shared memory containing registered containers
|
|
282
|
+
* @param context - Operation context with routing parameters
|
|
283
|
+
* @param logger - Logger for tracking routing operations
|
|
284
|
+
*/
|
|
285
|
+
async onRequest(
|
|
286
|
+
@A_Inject(A_Memory) memory: A_Memory<{ containers: Array<A_Container> }>,
|
|
287
|
+
@A_Inject(A_ChannelRequest) context: A_ChannelRequest<{ container: string, command: A_TYPES__Command_Serialized }>,
|
|
288
|
+
@A_Inject(A_Logger) logger: A_Logger,
|
|
289
|
+
): Promise<void> {
|
|
290
|
+
|
|
291
|
+
logger.info(`Channel: Routing command ${context.params.command.code} to container ${context.params.container}`);
|
|
292
|
+
|
|
293
|
+
// Get all registered containers from shared memory
|
|
294
|
+
const containers = await memory.get('containers') || [];
|
|
295
|
+
|
|
296
|
+
// Find target container by name (supports both exact match and camelCase conversion)
|
|
297
|
+
const target = containers
|
|
298
|
+
.find(c => A_FormatterHelper.toCamelCase(c.name) === A_FormatterHelper.toCamelCase(context.params.container)
|
|
299
|
+
|| c.name === context.params.container
|
|
300
|
+
)
|
|
301
|
+
|
|
302
|
+
// Resolve the command constructor in the target container's scope
|
|
303
|
+
const commandConstructor = target?.scope.resolveConstructor<A_Command>(context.params.command.code);
|
|
304
|
+
|
|
305
|
+
if (!commandConstructor) {
|
|
306
|
+
throw new A_Error(`Channel: Unable to find command constructor for ${context.params.command.code} in container ${context.params.container}`);
|
|
307
|
+
}
|
|
163
308
|
|
|
164
|
-
|
|
165
|
-
|
|
309
|
+
// Reconstruct the command from serialized data
|
|
310
|
+
const command = new commandConstructor(context.params.command);
|
|
166
311
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
A_Context.root.register(failCommand);
|
|
170
|
-
await failCommand.execute();
|
|
312
|
+
// Register the command in the target container's scope
|
|
313
|
+
target?.scope.register(command);
|
|
171
314
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
console.log(`Fail command - Errors:`, Array.from(failCommand.errors?.values() || []));
|
|
175
|
-
}
|
|
315
|
+
// Execute the command in the target service
|
|
316
|
+
await command.execute();
|
|
176
317
|
|
|
177
|
-
//
|
|
178
|
-
|
|
318
|
+
// Serialize the result and send it back
|
|
319
|
+
const serialized = command.toJSON();
|
|
179
320
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
FileProcessEvents
|
|
184
|
-
> { }
|
|
321
|
+
context.succeed(serialized);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
185
324
|
|
|
186
|
-
class FileProcessor extends A_Component {
|
|
187
325
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
326
|
+
// ============================================================================
|
|
327
|
+
// ====================== Service Container Definition =======================
|
|
328
|
+
// ============================================================================
|
|
191
329
|
|
|
192
|
-
|
|
193
|
-
|
|
330
|
+
/**
|
|
331
|
+
* Base Service Container
|
|
332
|
+
*
|
|
333
|
+
* A reusable container class that automatically registers itself
|
|
334
|
+
* in shared memory during the concept loading phase. This enables
|
|
335
|
+
* the channel to discover and route commands to different services.
|
|
336
|
+
*
|
|
337
|
+
* Each service instance:
|
|
338
|
+
* - Registers itself in shared memory during startup
|
|
339
|
+
* - Makes itself discoverable for command routing
|
|
340
|
+
* - Provides a scope for command execution
|
|
341
|
+
*/
|
|
342
|
+
class Service extends A_Container {
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* Container initialization during concept loading
|
|
346
|
+
*
|
|
347
|
+
* This method runs during the concept loading phase and ensures
|
|
348
|
+
* that all service containers are registered in shared memory
|
|
349
|
+
* so they can be discovered by the routing channel.
|
|
350
|
+
*
|
|
351
|
+
* @param memory - Shared memory for storing container registry
|
|
352
|
+
* @param logger - Logger for tracking service registration
|
|
353
|
+
*/
|
|
354
|
+
@A_Concept.Load()
|
|
355
|
+
async init(
|
|
356
|
+
@A_Inject(A_Memory) memory: A_Memory<{ containers: Array<A_Container> }>,
|
|
357
|
+
@A_Inject(A_Logger) logger: A_Logger,
|
|
194
358
|
) {
|
|
195
|
-
|
|
359
|
+
logger.info(`Registering container ${this.name} in shared memory`);
|
|
196
360
|
|
|
197
|
-
//
|
|
198
|
-
|
|
199
|
-
console.log(`Validating file: ${filePath}`);
|
|
200
|
-
await new Promise(resolve => setTimeout(resolve, 100));
|
|
361
|
+
// Get existing container registry or create new one
|
|
362
|
+
const containers = await memory.get('containers') || [];
|
|
201
363
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
await new Promise(resolve => setTimeout(resolve, 200));
|
|
364
|
+
// Add this container to the registry
|
|
365
|
+
containers.push(this);
|
|
205
366
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
await new Promise(resolve => setTimeout(resolve, 50));
|
|
209
|
-
|
|
210
|
-
await memory.set('outputPath', `processed_${filePath}`);
|
|
211
|
-
await memory.set('size', 1024);
|
|
367
|
+
// Store updated registry in shared memory
|
|
368
|
+
await memory.set('containers', containers);
|
|
212
369
|
}
|
|
213
370
|
}
|
|
214
371
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
A_Context.reset();
|
|
219
|
-
A_Context.root.register(FileProcessor);
|
|
372
|
+
// ============================================================================
|
|
373
|
+
// ====================== Application Setup and Execution ===================
|
|
374
|
+
// ============================================================================
|
|
220
375
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
376
|
+
/**
|
|
377
|
+
* Multi-Service Command Processing Demonstration
|
|
378
|
+
*
|
|
379
|
+
* This example demonstrates how to set up and execute commands
|
|
380
|
+
* across multiple services using the A_Concept architecture.
|
|
381
|
+
*
|
|
382
|
+
* Architecture Overview:
|
|
383
|
+
* - Two separate service containers (ServiceA and ServiceB)
|
|
384
|
+
* - Shared memory context for inter-service communication
|
|
385
|
+
* - Distributed command processing with lifecycle management
|
|
386
|
+
* - State tracking and result aggregation
|
|
387
|
+
*/
|
|
388
|
+
(async () => {
|
|
389
|
+
// ============================================================================
|
|
390
|
+
// ====================== Shared Memory Configuration ========================
|
|
391
|
+
// ============================================================================
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* Shared Memory Context
|
|
395
|
+
*
|
|
396
|
+
* Creates a shared memory space that will be accessible by both services.
|
|
397
|
+
* This enables inter-service communication and state sharing during
|
|
398
|
+
* command execution.
|
|
399
|
+
*/
|
|
400
|
+
const sharedMemory = new A_MemoryContext();
|
|
401
|
+
|
|
402
|
+
// ============================================================================
|
|
403
|
+
// ====================== Service Container Setup ============================
|
|
404
|
+
// ============================================================================
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* Service A Container
|
|
408
|
+
*
|
|
409
|
+
* Specialized service for handling the initial phases of command processing.
|
|
410
|
+
* Contains its own processor, routing channel, and shared dependencies.
|
|
411
|
+
*
|
|
412
|
+
* Components:
|
|
413
|
+
* - ServiceA_MyCommandProcessor: Handles pre-processing and main logic
|
|
414
|
+
* - SimpleChannel: Routes commands between services
|
|
415
|
+
* - A_Memory: Provides access to shared state
|
|
416
|
+
* - A_StateMachine: Manages command lifecycle transitions
|
|
417
|
+
* - A_Logger: Provides scoped logging
|
|
418
|
+
*/
|
|
419
|
+
const containerA = new Service({
|
|
420
|
+
name: 'ServiceA',
|
|
421
|
+
fragments: [sharedMemory], // Share memory context between services
|
|
422
|
+
components: [
|
|
423
|
+
ServiceA_MyCommandProcessor, // Service-specific command processor
|
|
424
|
+
SimpleChannel, // Inter-service communication channel
|
|
425
|
+
A_Memory, // Memory management
|
|
426
|
+
A_StateMachine, // State machine for command lifecycle
|
|
427
|
+
A_Logger // Scoped logging
|
|
428
|
+
],
|
|
429
|
+
entities: [myCommand], // Register command entity for this service
|
|
224
430
|
});
|
|
225
431
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
432
|
+
/**
|
|
433
|
+
* Service B Container
|
|
434
|
+
*
|
|
435
|
+
* Specialized service for handling secondary processing and finalization.
|
|
436
|
+
* Shares memory context with Service A but has its own processor logic.
|
|
437
|
+
*
|
|
438
|
+
* Note: Service B doesn't include SimpleChannel as it's primarily
|
|
439
|
+
* a target for routed commands rather than an initiator.
|
|
440
|
+
*/
|
|
441
|
+
const containerB = new Service({
|
|
442
|
+
name: 'ServiceB',
|
|
443
|
+
fragments: [sharedMemory], // Same shared memory as Service A
|
|
444
|
+
components: [
|
|
445
|
+
ServiceB_MyCommandProcessor, // Service-specific command processor
|
|
446
|
+
A_Memory, // Memory management (shared)
|
|
447
|
+
A_StateMachine, // State machine for command lifecycle
|
|
448
|
+
A_Logger // Scoped logging
|
|
449
|
+
],
|
|
450
|
+
entities: [myCommand], // Register command entity for this service
|
|
451
|
+
});
|
|
230
452
|
|
|
231
|
-
//
|
|
232
|
-
|
|
453
|
+
// ============================================================================
|
|
454
|
+
// ====================== Concept Architecture Setup =========================
|
|
455
|
+
// ============================================================================
|
|
456
|
+
|
|
457
|
+
/**
|
|
458
|
+
* A_Concept - Application Architecture
|
|
459
|
+
*
|
|
460
|
+
* Defines the overall application architecture by combining:
|
|
461
|
+
* - Multiple service containers
|
|
462
|
+
* - Shared components available across all services
|
|
463
|
+
* - Global dependency injection configuration
|
|
464
|
+
*
|
|
465
|
+
* This creates a distributed system where commands can be processed
|
|
466
|
+
* across multiple services while maintaining shared state and communication.
|
|
467
|
+
*/
|
|
468
|
+
const concept = new A_Concept({
|
|
469
|
+
containers: [containerA, containerB], // Register both service containers
|
|
470
|
+
components: [
|
|
471
|
+
SimpleChannel, // Global routing channel
|
|
472
|
+
A_Memory, // Global memory management
|
|
473
|
+
A_Logger // Global logging system
|
|
474
|
+
],
|
|
475
|
+
});
|
|
233
476
|
|
|
234
|
-
|
|
477
|
+
console.log('šļø Concept architecture defined with distributed services');
|
|
478
|
+
|
|
479
|
+
// ============================================================================
|
|
480
|
+
// ====================== System Initialization ==============================
|
|
481
|
+
// ============================================================================
|
|
482
|
+
|
|
483
|
+
/**
|
|
484
|
+
* Load and Initialize the Distributed System
|
|
485
|
+
*
|
|
486
|
+
* This triggers:
|
|
487
|
+
* 1. Container registration in shared memory
|
|
488
|
+
* 2. Component dependency resolution
|
|
489
|
+
* 3. Service discovery and routing table setup
|
|
490
|
+
* 4. Shared state initialization
|
|
491
|
+
*/
|
|
492
|
+
console.log('ā” Loading and initializing distributed system...');
|
|
493
|
+
await concept.load();
|
|
494
|
+
console.log('ā
System loaded - all services are ready\n');
|
|
495
|
+
|
|
496
|
+
// ============================================================================
|
|
497
|
+
// ====================== Command Creation and Execution =====================
|
|
498
|
+
// ============================================================================
|
|
499
|
+
|
|
500
|
+
/**
|
|
501
|
+
* Create Command Instance
|
|
502
|
+
*
|
|
503
|
+
* Instantiate the command with initial parameters.
|
|
504
|
+
* The command will go through the complete lifecycle:
|
|
505
|
+
* CREATED ā INITIALIZED ā COMPILED ā EXECUTING ā COMPLETED/FAILED
|
|
506
|
+
*/
|
|
507
|
+
const command = new myCommand({ userId: '123' });
|
|
508
|
+
console.log(`š Created command: ${command.id} for user: 123`);
|
|
509
|
+
console.log(` Initial status: ${command.status}`);
|
|
510
|
+
|
|
511
|
+
/**
|
|
512
|
+
* Register Command in Service A
|
|
513
|
+
*
|
|
514
|
+
* Register the command in Service A's scope, making it available
|
|
515
|
+
* for dependency injection and lifecycle management within that service.
|
|
516
|
+
*/
|
|
517
|
+
containerA.scope.register(command);
|
|
518
|
+
console.log('š Command registered in ServiceA scope');
|
|
519
|
+
|
|
520
|
+
/**
|
|
521
|
+
* Execute Distributed Command
|
|
522
|
+
*
|
|
523
|
+
* This will trigger:
|
|
524
|
+
* 1. ServiceA_MyCommandProcessor.pre() - Pre-processing setup
|
|
525
|
+
* 2. ServiceA_MyCommandProcessor.main() - Route to ServiceB
|
|
526
|
+
* 3. ServiceB_MyCommandProcessor processing - Secondary processing
|
|
527
|
+
* 4. ServiceA_MyCommandProcessor.post() - Result aggregation
|
|
528
|
+
* 5. State transitions and result compilation
|
|
529
|
+
*/
|
|
530
|
+
console.log('š Executing distributed command across services...\n');
|
|
235
531
|
await command.execute();
|
|
236
532
|
|
|
237
|
-
|
|
238
|
-
|
|
533
|
+
// ============================================================================
|
|
534
|
+
// ====================== Results and Logging ================================
|
|
535
|
+
// ============================================================================
|
|
239
536
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
537
|
+
/**
|
|
538
|
+
* Result Analysis and Logging
|
|
539
|
+
*
|
|
540
|
+
* After execution, analyze the command state and results.
|
|
541
|
+
* The logger is resolved from the concept scope to provide
|
|
542
|
+
* centralized logging across all services.
|
|
543
|
+
*/
|
|
544
|
+
const logger = concept.scope.resolve(A_Logger)!;
|
|
243
545
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
await errorHandlingExample();
|
|
249
|
-
await customEventsExample();
|
|
546
|
+
// Log final execution status
|
|
547
|
+
logger.info('⨠Command execution completed');
|
|
548
|
+
logger.info(` Final status: ${command.status}`);
|
|
549
|
+
logger.info(' Command state:', command.toJSON());
|
|
250
550
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
}
|
|
551
|
+
console.log('\nš Multi-service command processing example completed!');
|
|
552
|
+
console.log('Check the logs above to see the distributed processing flow.');
|
|
553
|
+
|
|
554
|
+
})();
|
|
256
555
|
|
|
257
|
-
// Export for use as module or run directly
|
|
258
|
-
export {
|
|
259
|
-
basicCommandExample,
|
|
260
|
-
typedCommandExample,
|
|
261
|
-
serializationExample,
|
|
262
|
-
errorHandlingExample,
|
|
263
|
-
customEventsExample,
|
|
264
|
-
runAllExamples
|
|
265
|
-
};
|
|
266
|
-
|
|
267
|
-
// Run if this file is executed directly
|
|
268
|
-
if (require.main === module) {
|
|
269
|
-
runAllExamples();
|
|
270
|
-
}
|