xcomponent-ai 0.2.2 → 0.3.0
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/EVENT-ACCUMULATION-GUIDE.md +505 -0
- package/EXTERNAL-API.md +719 -0
- package/LLM-GUIDE.md +575 -0
- package/QUICKSTART.md +1 -1
- package/SCALABILITY.md +455 -0
- package/dist/cli.js +170 -63
- package/dist/cli.js.map +1 -1
- package/dist/component-registry.d.ts +35 -4
- package/dist/component-registry.d.ts.map +1 -1
- package/dist/component-registry.js +194 -9
- package/dist/component-registry.js.map +1 -1
- package/dist/external-broker-api.d.ts +205 -0
- package/dist/external-broker-api.d.ts.map +1 -0
- package/dist/external-broker-api.js +222 -0
- package/dist/external-broker-api.js.map +1 -0
- package/dist/fsm-runtime.d.ts +47 -17
- package/dist/fsm-runtime.d.ts.map +1 -1
- package/dist/fsm-runtime.js +333 -136
- package/dist/fsm-runtime.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -1
- package/dist/index.js.map +1 -1
- package/dist/mermaid-generator.d.ts.map +1 -1
- package/dist/mermaid-generator.js +1 -17
- package/dist/mermaid-generator.js.map +1 -1
- package/dist/message-broker.d.ts +116 -0
- package/dist/message-broker.d.ts.map +1 -0
- package/dist/message-broker.js +225 -0
- package/dist/message-broker.js.map +1 -0
- package/dist/types.d.ts +92 -19
- package/dist/types.d.ts.map +1 -1
- package/examples/advanced-patterns-demo.yaml +339 -0
- package/examples/cross-component-demo.yaml +68 -0
- package/examples/distributed-demo/README.md +234 -0
- package/examples/distributed-demo/order.yaml +71 -0
- package/examples/distributed-demo/payment.yaml +60 -0
- package/examples/event-accumulation-demo.yaml +172 -0
- package/examples/explicit-transitions-demo.yaml +236 -0
- package/examples/payment-receiver.yaml +56 -0
- package/package.json +8 -1
- package/public/dashboard.html +647 -110
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
# Distributed Multi-Process Demo
|
|
2
|
+
|
|
3
|
+
This demo shows how to run xcomponent-ai components in **separate processes** communicating via **Redis Pub/Sub**.
|
|
4
|
+
|
|
5
|
+
## Architecture
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
┌─────────────────────┐ Redis ┌─────────────────────┐
|
|
9
|
+
│ Process 1 │ Pub/Sub │ Process 2 │
|
|
10
|
+
│ │ │ │
|
|
11
|
+
│ OrderComponent │──────────────────────▶│ PaymentComponent │
|
|
12
|
+
│ Port: 3001 │ PROCESS event │ Port: 3002 │
|
|
13
|
+
│ │ │ │
|
|
14
|
+
│ Order FSM │ │ Payment FSM │
|
|
15
|
+
│ - Created │ │ - Pending │
|
|
16
|
+
│ - Validated ───────┼───────────────────────┼──▶ Processing │
|
|
17
|
+
│ - Completed │ │ - Completed │
|
|
18
|
+
└─────────────────────┘ └─────────────────────┘
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
**How it works:**
|
|
22
|
+
1. Process 1 (OrderComponent) runs on port 3001
|
|
23
|
+
2. Process 2 (PaymentComponent) runs on port 3002
|
|
24
|
+
3. When Order transitions to "Validated", it publishes a message to Redis
|
|
25
|
+
4. PaymentComponent receives the message via Redis and triggers the transition
|
|
26
|
+
|
|
27
|
+
## Prerequisites
|
|
28
|
+
|
|
29
|
+
1. **Install Redis:**
|
|
30
|
+
```bash
|
|
31
|
+
# macOS
|
|
32
|
+
brew install redis
|
|
33
|
+
brew services start redis
|
|
34
|
+
|
|
35
|
+
# Ubuntu/Debian
|
|
36
|
+
sudo apt-get install redis-server
|
|
37
|
+
sudo systemctl start redis
|
|
38
|
+
|
|
39
|
+
# Docker
|
|
40
|
+
docker run -d -p 6379:6379 redis:7-alpine
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
2. **Verify Redis is running:**
|
|
44
|
+
```bash
|
|
45
|
+
redis-cli ping
|
|
46
|
+
# Should return: PONG
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
3. **Install xcomponent-ai with Redis support:**
|
|
50
|
+
```bash
|
|
51
|
+
npm install -g xcomponent-ai redis
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Running the Demo
|
|
55
|
+
|
|
56
|
+
### Step 1: Start Process 1 (OrderComponent)
|
|
57
|
+
|
|
58
|
+
In **Terminal 1:**
|
|
59
|
+
```bash
|
|
60
|
+
xcomponent-ai serve examples/distributed-demo/order.yaml \
|
|
61
|
+
--port 3001 \
|
|
62
|
+
--broker redis://localhost:6379
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Expected output:
|
|
66
|
+
```
|
|
67
|
+
📡 Mode: Distributed (broker: redis://localhost:6379)
|
|
68
|
+
🚀 xcomponent-ai Runtime Started
|
|
69
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
70
|
+
|
|
71
|
+
📦 Component: OrderComponent
|
|
72
|
+
Machines:
|
|
73
|
+
- Order (3 states, 3 transitions)
|
|
74
|
+
|
|
75
|
+
🌐 API Server: http://localhost:3001
|
|
76
|
+
📊 Dashboard: http://localhost:3001/dashboard.html
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Step 2: Start Process 2 (PaymentComponent)
|
|
80
|
+
|
|
81
|
+
In **Terminal 2:**
|
|
82
|
+
```bash
|
|
83
|
+
xcomponent-ai serve examples/distributed-demo/payment.yaml \
|
|
84
|
+
--port 3002 \
|
|
85
|
+
--broker redis://localhost:6379
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Expected output:
|
|
89
|
+
```
|
|
90
|
+
📡 Mode: Distributed (broker: redis://localhost:6379)
|
|
91
|
+
🚀 xcomponent-ai Runtime Started
|
|
92
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
93
|
+
|
|
94
|
+
📦 Component: PaymentComponent
|
|
95
|
+
Machines:
|
|
96
|
+
- Payment (4 states, 3 transitions)
|
|
97
|
+
|
|
98
|
+
🌐 API Server: http://localhost:3002
|
|
99
|
+
📊 Dashboard: http://localhost:3002/dashboard.html
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Step 3: Test Cross-Process Communication
|
|
103
|
+
|
|
104
|
+
In **Terminal 3:**
|
|
105
|
+
|
|
106
|
+
1. **Create a Payment instance in Process 2:**
|
|
107
|
+
```bash
|
|
108
|
+
curl -X POST http://localhost:3002/api/components/PaymentComponent/instances \
|
|
109
|
+
-H "Content-Type: application/json" \
|
|
110
|
+
-d '{
|
|
111
|
+
"machineName": "Payment",
|
|
112
|
+
"context": {
|
|
113
|
+
"orderId": "ORD-001",
|
|
114
|
+
"amount": 1000,
|
|
115
|
+
"customerId": "CUST-001"
|
|
116
|
+
}
|
|
117
|
+
}'
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Note the `instanceId` returned (e.g., `abc-123-def-456`).
|
|
121
|
+
|
|
122
|
+
2. **Create an Order instance in Process 1:**
|
|
123
|
+
```bash
|
|
124
|
+
curl -X POST http://localhost:3001/api/components/OrderComponent/instances \
|
|
125
|
+
-H "Content-Type: application/json" \
|
|
126
|
+
-d '{
|
|
127
|
+
"machineName": "Order",
|
|
128
|
+
"context": {
|
|
129
|
+
"orderId": "ORD-001",
|
|
130
|
+
"amount": 1000,
|
|
131
|
+
"customerId": "CUST-001"
|
|
132
|
+
}
|
|
133
|
+
}'
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Note the `instanceId` returned (e.g., `xyz-789-uvw-012`).
|
|
137
|
+
|
|
138
|
+
3. **Trigger VALIDATE on Order (Process 1):**
|
|
139
|
+
```bash
|
|
140
|
+
ORDER_ID="xyz-789-uvw-012" # Replace with actual ID from step 2
|
|
141
|
+
|
|
142
|
+
curl -X POST http://localhost:3001/api/instances/$ORDER_ID/events \
|
|
143
|
+
-H "Content-Type: application/json" \
|
|
144
|
+
-d '{
|
|
145
|
+
"type": "VALIDATE"
|
|
146
|
+
}'
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
4. **Verify Payment transitioned in Process 2:**
|
|
150
|
+
```bash
|
|
151
|
+
PAYMENT_ID="abc-123-def-456" # Replace with actual ID from step 1
|
|
152
|
+
|
|
153
|
+
curl http://localhost:3002/api/instances/$PAYMENT_ID
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
You should see the Payment instance now in `Processing` state!
|
|
157
|
+
|
|
158
|
+
### Step 4: Observe Cross-Process Communication
|
|
159
|
+
|
|
160
|
+
**In Terminal 1 (OrderComponent):**
|
|
161
|
+
You'll see:
|
|
162
|
+
```
|
|
163
|
+
[2:34:01 PM] [OrderComponent] xyz-789-uvw-012: Created → Validated (event: VALIDATE)
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
**In Terminal 2 (PaymentComponent):**
|
|
167
|
+
You'll see:
|
|
168
|
+
```
|
|
169
|
+
[2:34:01 PM] [PaymentComponent] abc-123-def-456: Pending → Processing (event: PROCESS)
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
**Magic!** The Order in Process 1 triggered the Payment in Process 2 via Redis Pub/Sub! 🎉
|
|
173
|
+
|
|
174
|
+
## Viewing Dashboards
|
|
175
|
+
|
|
176
|
+
Open in your browser:
|
|
177
|
+
- **Process 1 Dashboard:** http://localhost:3001/dashboard.html
|
|
178
|
+
- **Process 2 Dashboard:** http://localhost:3002/dashboard.html
|
|
179
|
+
|
|
180
|
+
You can see real-time state transitions in both processes independently.
|
|
181
|
+
|
|
182
|
+
## Scaling Up
|
|
183
|
+
|
|
184
|
+
You can run **multiple instances** of each process for load balancing:
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
# 2 instances of OrderComponent
|
|
188
|
+
xcomponent-ai serve order.yaml --port 3001 --broker redis://localhost:6379 &
|
|
189
|
+
xcomponent-ai serve order.yaml --port 3011 --broker redis://localhost:6379 &
|
|
190
|
+
|
|
191
|
+
# 3 instances of PaymentComponent
|
|
192
|
+
xcomponent-ai serve payment.yaml --port 3002 --broker redis://localhost:6379 &
|
|
193
|
+
xcomponent-ai serve payment.yaml --port 3012 --broker redis://localhost:6379 &
|
|
194
|
+
xcomponent-ai serve payment.yaml --port 3022 --broker redis://localhost:6379 &
|
|
195
|
+
|
|
196
|
+
# Add nginx load balancer in front
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
All instances subscribe to the same Redis channels, enabling **horizontal scaling**.
|
|
200
|
+
|
|
201
|
+
## Environment Variable
|
|
202
|
+
|
|
203
|
+
Instead of `--broker` flag, you can use:
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
export XCOMPONENT_BROKER_URL=redis://localhost:6379
|
|
207
|
+
|
|
208
|
+
xcomponent-ai serve order.yaml --port 3001
|
|
209
|
+
xcomponent-ai serve payment.yaml --port 3002
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
## Production Deployment
|
|
213
|
+
|
|
214
|
+
For production, use:
|
|
215
|
+
- **Redis Cluster** for high availability
|
|
216
|
+
- **Redis Sentinel** for automatic failover
|
|
217
|
+
- **Kubernetes** for orchestration
|
|
218
|
+
- **Load balancer** (nginx, HAProxy) for API endpoints
|
|
219
|
+
|
|
220
|
+
See [SCALABILITY.md](../../SCALABILITY.md) for detailed production patterns.
|
|
221
|
+
|
|
222
|
+
## Switching Back to In-Memory
|
|
223
|
+
|
|
224
|
+
To run both components in a **single process** (in-memory mode):
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
xcomponent-ai serve \
|
|
228
|
+
examples/distributed-demo/order.yaml \
|
|
229
|
+
examples/distributed-demo/payment.yaml \
|
|
230
|
+
--port 3000
|
|
231
|
+
# No --broker flag = in-memory mode by default
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
**Zero code changes!** Just configuration. 🚀
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# Order Component - Process 1
|
|
2
|
+
# This component runs in its own process and communicates with PaymentComponent via Redis
|
|
3
|
+
|
|
4
|
+
name: OrderComponent
|
|
5
|
+
version: 1.0.0
|
|
6
|
+
metadata:
|
|
7
|
+
description: Order management system (distributed process 1)
|
|
8
|
+
|
|
9
|
+
stateMachines:
|
|
10
|
+
- name: Order
|
|
11
|
+
initialState: Created
|
|
12
|
+
contextSchema:
|
|
13
|
+
orderId:
|
|
14
|
+
type: text
|
|
15
|
+
label: Order ID
|
|
16
|
+
required: true
|
|
17
|
+
placeholder: ORD-001
|
|
18
|
+
amount:
|
|
19
|
+
type: number
|
|
20
|
+
label: Total Amount
|
|
21
|
+
required: true
|
|
22
|
+
min: 1
|
|
23
|
+
customerId:
|
|
24
|
+
type: text
|
|
25
|
+
label: Customer ID
|
|
26
|
+
required: true
|
|
27
|
+
placeholder: CUST-001
|
|
28
|
+
|
|
29
|
+
states:
|
|
30
|
+
- name: Created
|
|
31
|
+
type: entry
|
|
32
|
+
description: Order created and awaiting validation
|
|
33
|
+
|
|
34
|
+
- name: Validated
|
|
35
|
+
type: regular
|
|
36
|
+
description: Order validated, payment triggered via Redis
|
|
37
|
+
# DISTRIBUTED CROSS-COMPONENT: Trigger payment in PaymentComponent (different process!)
|
|
38
|
+
cascadingRules:
|
|
39
|
+
- targetComponent: PaymentComponent
|
|
40
|
+
targetMachine: Payment
|
|
41
|
+
targetState: Pending
|
|
42
|
+
event: PROCESS
|
|
43
|
+
payload:
|
|
44
|
+
orderId: "{{orderId}}"
|
|
45
|
+
amount: "{{amount}}"
|
|
46
|
+
customerId: "{{customerId}}"
|
|
47
|
+
|
|
48
|
+
- name: Completed
|
|
49
|
+
type: final
|
|
50
|
+
description: Order completed successfully
|
|
51
|
+
|
|
52
|
+
- name: Cancelled
|
|
53
|
+
type: error
|
|
54
|
+
description: Order cancelled
|
|
55
|
+
|
|
56
|
+
transitions:
|
|
57
|
+
- from: Created
|
|
58
|
+
to: Validated
|
|
59
|
+
event: VALIDATE
|
|
60
|
+
type: triggerable
|
|
61
|
+
description: Validate order and trigger payment
|
|
62
|
+
|
|
63
|
+
- from: Validated
|
|
64
|
+
to: Completed
|
|
65
|
+
event: COMPLETE
|
|
66
|
+
type: triggerable
|
|
67
|
+
|
|
68
|
+
- from: Created
|
|
69
|
+
to: Cancelled
|
|
70
|
+
event: CANCEL
|
|
71
|
+
type: triggerable
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Payment Component - Process 2
|
|
2
|
+
# This component runs in a SEPARATE process and receives events from OrderComponent via Redis
|
|
3
|
+
|
|
4
|
+
name: PaymentComponent
|
|
5
|
+
version: 1.0.0
|
|
6
|
+
metadata:
|
|
7
|
+
description: Payment processing system (distributed process 2)
|
|
8
|
+
|
|
9
|
+
stateMachines:
|
|
10
|
+
- name: Payment
|
|
11
|
+
initialState: Pending
|
|
12
|
+
contextSchema:
|
|
13
|
+
orderId:
|
|
14
|
+
type: text
|
|
15
|
+
label: Order ID
|
|
16
|
+
required: true
|
|
17
|
+
amount:
|
|
18
|
+
type: number
|
|
19
|
+
label: Amount
|
|
20
|
+
required: true
|
|
21
|
+
customerId:
|
|
22
|
+
type: text
|
|
23
|
+
label: Customer ID
|
|
24
|
+
required: true
|
|
25
|
+
|
|
26
|
+
states:
|
|
27
|
+
- name: Pending
|
|
28
|
+
type: entry
|
|
29
|
+
description: Payment awaiting processing (receives PROCESS from OrderComponent)
|
|
30
|
+
|
|
31
|
+
- name: Processing
|
|
32
|
+
type: regular
|
|
33
|
+
description: Payment being processed
|
|
34
|
+
|
|
35
|
+
- name: Completed
|
|
36
|
+
type: final
|
|
37
|
+
description: Payment completed successfully
|
|
38
|
+
|
|
39
|
+
- name: Failed
|
|
40
|
+
type: error
|
|
41
|
+
description: Payment failed
|
|
42
|
+
|
|
43
|
+
transitions:
|
|
44
|
+
- from: Pending
|
|
45
|
+
to: Processing
|
|
46
|
+
event: PROCESS
|
|
47
|
+
type: triggerable
|
|
48
|
+
description: Start payment processing (triggered by OrderComponent via Redis)
|
|
49
|
+
|
|
50
|
+
- from: Processing
|
|
51
|
+
to: Completed
|
|
52
|
+
event: CONFIRM
|
|
53
|
+
type: triggerable
|
|
54
|
+
description: Confirm payment success
|
|
55
|
+
|
|
56
|
+
- from: Processing
|
|
57
|
+
to: Failed
|
|
58
|
+
event: FAIL
|
|
59
|
+
type: triggerable
|
|
60
|
+
description: Mark payment as failed
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
# Event Accumulation Demo
|
|
2
|
+
# Shows how to accumulate multiple events and use EXPLICIT CONTROL for transitions
|
|
3
|
+
#
|
|
4
|
+
# Use Case: Trading Order that receives multiple execution notifications
|
|
5
|
+
# and transitions to "Fully Executed" only when all quantity is executed
|
|
6
|
+
#
|
|
7
|
+
# Key Pattern: sender.sendToSelf() for explicit transition control
|
|
8
|
+
|
|
9
|
+
name: TradingComponent
|
|
10
|
+
version: 1.0.0
|
|
11
|
+
metadata:
|
|
12
|
+
description: Trading order with partial executions and explicit control
|
|
13
|
+
|
|
14
|
+
# Define triggered methods that accumulate data and EXPLICITLY control transitions
|
|
15
|
+
triggeredMethods:
|
|
16
|
+
# Accumulates execution data and EXPLICITLY decides when to transition
|
|
17
|
+
accumulateExecution: |
|
|
18
|
+
async function(event, context, sender) {
|
|
19
|
+
// Initialize if first execution
|
|
20
|
+
if (!context.executedQuantity) {
|
|
21
|
+
context.executedQuantity = 0;
|
|
22
|
+
}
|
|
23
|
+
if (!context.executions) {
|
|
24
|
+
context.executions = [];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Add executed quantity from event
|
|
28
|
+
const executedQty = event.payload.quantity || 0;
|
|
29
|
+
context.executedQuantity += executedQty;
|
|
30
|
+
|
|
31
|
+
// Track individual executions for audit
|
|
32
|
+
context.executions.push({
|
|
33
|
+
quantity: executedQty,
|
|
34
|
+
price: event.payload.price,
|
|
35
|
+
timestamp: event.timestamp,
|
|
36
|
+
executionId: event.payload.executionId
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
console.log(`Accumulated: ${context.executedQuantity}/${context.totalQuantity}`);
|
|
40
|
+
|
|
41
|
+
// EXPLICIT CONTROL: Decide when to transition to FullyExecuted
|
|
42
|
+
if (context.executedQuantity >= context.totalQuantity) {
|
|
43
|
+
console.log(`Order ${context.orderId} is now fully executed!`);
|
|
44
|
+
// Send event to self to trigger transition to FullyExecuted
|
|
45
|
+
await sender.sendToSelf({
|
|
46
|
+
type: 'FULLY_EXECUTED',
|
|
47
|
+
payload: {
|
|
48
|
+
totalExecuted: context.executedQuantity,
|
|
49
|
+
executionCount: context.executions.length,
|
|
50
|
+
averagePrice: context.executions.reduce((sum, e) => sum + e.price, 0) / context.executions.length
|
|
51
|
+
},
|
|
52
|
+
timestamp: Date.now()
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
# Handle completion
|
|
58
|
+
handleCompletion: |
|
|
59
|
+
async function(event, context, sender) {
|
|
60
|
+
console.log(`Order ${context.orderId} completed!`);
|
|
61
|
+
console.log(` Total executed: ${event.payload.totalExecuted}`);
|
|
62
|
+
console.log(` Executions: ${event.payload.executionCount}`);
|
|
63
|
+
console.log(` Average price: ${event.payload.averagePrice}`);
|
|
64
|
+
|
|
65
|
+
context.completedAt = Date.now();
|
|
66
|
+
context.stats = event.payload;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
stateMachines:
|
|
70
|
+
- name: TradingOrder
|
|
71
|
+
initialState: Created
|
|
72
|
+
|
|
73
|
+
contextSchema:
|
|
74
|
+
orderId:
|
|
75
|
+
type: text
|
|
76
|
+
label: Order ID
|
|
77
|
+
required: true
|
|
78
|
+
symbol:
|
|
79
|
+
type: text
|
|
80
|
+
label: Symbol (e.g., AAPL)
|
|
81
|
+
required: true
|
|
82
|
+
totalQuantity:
|
|
83
|
+
type: number
|
|
84
|
+
label: Total Quantity to Execute
|
|
85
|
+
required: true
|
|
86
|
+
min: 1
|
|
87
|
+
side:
|
|
88
|
+
type: select
|
|
89
|
+
label: Side
|
|
90
|
+
options:
|
|
91
|
+
- BUY
|
|
92
|
+
- SELL
|
|
93
|
+
required: true
|
|
94
|
+
|
|
95
|
+
states:
|
|
96
|
+
- name: Created
|
|
97
|
+
type: entry
|
|
98
|
+
description: Order created, waiting for market submission
|
|
99
|
+
|
|
100
|
+
- name: Submitted
|
|
101
|
+
type: regular
|
|
102
|
+
description: Order submitted to market
|
|
103
|
+
|
|
104
|
+
- name: PartiallyExecuted
|
|
105
|
+
type: regular
|
|
106
|
+
description: Order partially executed, waiting for more fills
|
|
107
|
+
|
|
108
|
+
- name: FullyExecuted
|
|
109
|
+
type: regular
|
|
110
|
+
description: Order fully executed
|
|
111
|
+
|
|
112
|
+
- name: Completed
|
|
113
|
+
type: final
|
|
114
|
+
description: Order completed (settlement done)
|
|
115
|
+
|
|
116
|
+
- name: Cancelled
|
|
117
|
+
type: error
|
|
118
|
+
description: Order cancelled
|
|
119
|
+
|
|
120
|
+
transitions:
|
|
121
|
+
# Submit order to market
|
|
122
|
+
- from: Created
|
|
123
|
+
to: Submitted
|
|
124
|
+
event: SUBMIT
|
|
125
|
+
type: triggerable
|
|
126
|
+
|
|
127
|
+
# First execution notification (Submitted → PartiallyExecuted)
|
|
128
|
+
- from: Submitted
|
|
129
|
+
to: PartiallyExecuted
|
|
130
|
+
event: EXECUTION_NOTIFICATION
|
|
131
|
+
type: triggerable
|
|
132
|
+
triggeredMethod: accumulateExecution
|
|
133
|
+
|
|
134
|
+
# SELF-LOOP: Subsequent execution notifications (PartiallyExecuted → PartiallyExecuted)
|
|
135
|
+
# Triggered method decides when to send FULLY_EXECUTED event
|
|
136
|
+
- from: PartiallyExecuted
|
|
137
|
+
to: PartiallyExecuted
|
|
138
|
+
event: EXECUTION_NOTIFICATION
|
|
139
|
+
type: triggerable
|
|
140
|
+
triggeredMethod: accumulateExecution
|
|
141
|
+
|
|
142
|
+
# EXPLICIT TRANSITION: Triggered by sender.sendToSelf() in accumulateExecution
|
|
143
|
+
# No guards! The business logic is in the triggered method
|
|
144
|
+
- from: PartiallyExecuted
|
|
145
|
+
to: FullyExecuted
|
|
146
|
+
event: FULLY_EXECUTED
|
|
147
|
+
type: triggerable
|
|
148
|
+
triggeredMethod: handleCompletion
|
|
149
|
+
|
|
150
|
+
# Also handle direct full execution from Submitted (single large fill)
|
|
151
|
+
- from: Submitted
|
|
152
|
+
to: FullyExecuted
|
|
153
|
+
event: FULLY_EXECUTED
|
|
154
|
+
type: triggerable
|
|
155
|
+
triggeredMethod: handleCompletion
|
|
156
|
+
|
|
157
|
+
# Settlement
|
|
158
|
+
- from: FullyExecuted
|
|
159
|
+
to: Completed
|
|
160
|
+
event: SETTLE
|
|
161
|
+
type: triggerable
|
|
162
|
+
|
|
163
|
+
# Cancellation
|
|
164
|
+
- from: Submitted
|
|
165
|
+
to: Cancelled
|
|
166
|
+
event: CANCEL
|
|
167
|
+
type: triggerable
|
|
168
|
+
|
|
169
|
+
- from: PartiallyExecuted
|
|
170
|
+
to: Cancelled
|
|
171
|
+
event: CANCEL
|
|
172
|
+
type: triggerable
|