@solidactions/sdk 0.1.1 → 0.2.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/README.md +25 -4
- package/dist/src/cli/cli.js +0 -0
- package/dist/src/testing/index.d.ts +13 -0
- package/dist/src/testing/index.d.ts.map +1 -0
- package/dist/src/testing/index.js +19 -0
- package/dist/src/testing/index.js.map +1 -0
- package/dist/src/testing/mock_server.d.ts +134 -0
- package/dist/src/testing/mock_server.d.ts.map +1 -0
- package/dist/src/testing/mock_server.js +613 -0
- package/dist/src/testing/mock_server.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/docs/sdk-reference.md +1207 -0
- package/package.json +6 -1
- package/.claude/settings.local.json +0 -7
- package/dist/dbos-config.schema.json +0 -132
- package/dist/src/cli/commands.d.ts +0 -3
- package/dist/src/cli/commands.d.ts.map +0 -1
- package/dist/src/cli/commands.js +0 -46
- package/dist/src/cli/commands.js.map +0 -1
- package/dist/src/datasource.d.ts +0 -109
- package/dist/src/datasource.d.ts.map +0 -1
- package/dist/src/datasource.js +0 -204
- package/dist/src/datasource.js.map +0 -1
- package/dist/src/dbos-executor.d.ts +0 -189
- package/dist/src/dbos-executor.d.ts.map +0 -1
- package/dist/src/dbos-executor.js +0 -817
- package/dist/src/dbos-executor.js.map +0 -1
- package/dist/src/dbos.d.ts +0 -519
- package/dist/src/dbos.d.ts.map +0 -1
- package/dist/src/dbos.js +0 -1282
- package/dist/src/dbos.js.map +0 -1
- package/dist/src/debouncer.d.ts +0 -33
- package/dist/src/debouncer.d.ts.map +0 -1
- package/dist/src/debouncer.js +0 -170
- package/dist/src/debouncer.js.map +0 -1
- package/dist/src/scheduler/crontab.d.ts +0 -14
- package/dist/src/scheduler/crontab.d.ts.map +0 -1
- package/dist/src/scheduler/crontab.js +0 -308
- package/dist/src/scheduler/crontab.js.map +0 -1
- package/dist/src/scheduler/scheduler.d.ts +0 -41
- package/dist/src/scheduler/scheduler.d.ts.map +0 -1
- package/dist/src/scheduler/scheduler.js +0 -165
- package/dist/src/scheduler/scheduler.js.map +0 -1
- package/dist/src/wfqueue.d.ts +0 -64
- package/dist/src/wfqueue.d.ts.map +0 -1
- package/dist/src/wfqueue.js +0 -147
- package/dist/src/wfqueue.js.map +0 -1
- package/docs/api-schema.md +0 -1441
- package/docs/migration-guide.md +0 -460
- package/docs/phase-14-changes.md +0 -156
- package/docs/solidsteps-ai-prompt.md +0 -534
- package/solidactions-ai-prompt.md +0 -1504
package/docs/api-schema.md
DELETED
|
@@ -1,1441 +0,0 @@
|
|
|
1
|
-
# DBOS HTTP API Schema
|
|
2
|
-
|
|
3
|
-
This document defines the HTTP API that must be implemented by the backend (Laravel) to support the DBOS TypeScript SDK.
|
|
4
|
-
|
|
5
|
-
## Overview
|
|
6
|
-
|
|
7
|
-
The SDK communicates with the backend exclusively via HTTP API calls. All workflow state, operations, messages, events, and streams are managed through these endpoints.
|
|
8
|
-
|
|
9
|
-
**Base URL**: Configured via `DBOS_API_URL` environment variable or `api.url` in config file.
|
|
10
|
-
|
|
11
|
-
## Authentication
|
|
12
|
-
|
|
13
|
-
All requests include a Bearer token in the Authorization header:
|
|
14
|
-
|
|
15
|
-
```
|
|
16
|
-
Authorization: Bearer <api_key>
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
The API key is configured via `DBOS_API_KEY` environment variable or `api.key` in config file.
|
|
20
|
-
|
|
21
|
-
## Common Headers
|
|
22
|
-
|
|
23
|
-
**Request Headers:**
|
|
24
|
-
|
|
25
|
-
```
|
|
26
|
-
Content-Type: application/json
|
|
27
|
-
Accept: application/json
|
|
28
|
-
Authorization: Bearer <api_key>
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
**Response Headers:**
|
|
32
|
-
|
|
33
|
-
```
|
|
34
|
-
Content-Type: application/json
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
## Error Responses
|
|
38
|
-
|
|
39
|
-
All error responses follow this format:
|
|
40
|
-
|
|
41
|
-
```json
|
|
42
|
-
{
|
|
43
|
-
"message": "Human-readable error message",
|
|
44
|
-
"type": "error_type", // Optional: specific error type
|
|
45
|
-
"workflowID": "uuid", // Optional: for workflow-specific errors
|
|
46
|
-
"retryAfter": 60 // Optional: seconds to wait (for 429)
|
|
47
|
-
}
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
### HTTP Status Code Mapping
|
|
51
|
-
|
|
52
|
-
| Status | SDK Exception | When to Return |
|
|
53
|
-
| ------ | ------------------------------ | ----------------------------------------------------- |
|
|
54
|
-
| 400 | `DBOSDataValidationError` | Invalid request body or parameters |
|
|
55
|
-
| 401 | `DBOSUnauthorizedError` | Invalid or missing API key |
|
|
56
|
-
| 403 | `DBOSForbiddenError` | Valid API key but insufficient permissions |
|
|
57
|
-
| 404 | `DBOSNotFoundError` | Resource not found (general) |
|
|
58
|
-
| 404 | `DBOSNonExistentWorkflowError` | Workflow not found (set `type: "workflow_not_found"`) |
|
|
59
|
-
| 409 | `DBOSWorkflowConflictError` | Workflow UUID conflict |
|
|
60
|
-
| 429 | `DBOSRateLimitedError` | Rate limit exceeded (include `retryAfter`) |
|
|
61
|
-
| 5xx | `DBOSServerError` | Server errors (SDK will retry with backoff) |
|
|
62
|
-
|
|
63
|
-
---
|
|
64
|
-
|
|
65
|
-
## Endpoints
|
|
66
|
-
|
|
67
|
-
### Health Check
|
|
68
|
-
|
|
69
|
-
#### GET /health
|
|
70
|
-
|
|
71
|
-
Verify API connectivity.
|
|
72
|
-
|
|
73
|
-
**Response 200:**
|
|
74
|
-
|
|
75
|
-
```json
|
|
76
|
-
{
|
|
77
|
-
"status": "ok"
|
|
78
|
-
}
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
---
|
|
82
|
-
|
|
83
|
-
## Workflow Endpoints
|
|
84
|
-
|
|
85
|
-
### Create Workflow
|
|
86
|
-
|
|
87
|
-
#### POST /workflows
|
|
88
|
-
|
|
89
|
-
Initialize a new workflow status record.
|
|
90
|
-
|
|
91
|
-
**Request Body:**
|
|
92
|
-
|
|
93
|
-
```json
|
|
94
|
-
{
|
|
95
|
-
"workflowUUID": "string", // Required: Unique workflow ID
|
|
96
|
-
"status": "string", // Required: Initial status (typically "PENDING" or "ENQUEUED")
|
|
97
|
-
"workflowName": "string", // Required: Function name
|
|
98
|
-
"workflowClassName": "string", // Required: Class name (empty string if none)
|
|
99
|
-
"workflowConfigName": "string", // Required: Config name (empty string if none)
|
|
100
|
-
"queueName": "string | null", // Optional: Queue name if enqueued
|
|
101
|
-
"authenticatedUser": "string", // Required: User ID (empty string if none)
|
|
102
|
-
"assumedRole": "string", // Required: Role (empty string if none)
|
|
103
|
-
"authenticatedRoles": ["string"], // Required: Array of roles
|
|
104
|
-
"request": {}, // Required: Request context object
|
|
105
|
-
"executorId": "string", // Required: Executor ID
|
|
106
|
-
"applicationVersion": "string", // Optional: App version
|
|
107
|
-
"applicationID": "string", // Required: Application ID
|
|
108
|
-
"input": "string | null", // Required: Serialized JSON input
|
|
109
|
-
"output": null, // Required: null on creation
|
|
110
|
-
"error": null, // Required: null on creation
|
|
111
|
-
"createdAt": 1234567890, // Required: Unix timestamp ms
|
|
112
|
-
"timeoutMS": 30000, // Optional: Workflow timeout
|
|
113
|
-
"deadlineEpochMS": 1234567890, // Optional: Absolute deadline
|
|
114
|
-
"deduplicationID": "string", // Optional: For queue deduplication
|
|
115
|
-
"priority": 0, // Required: Queue priority (0 = highest)
|
|
116
|
-
"queuePartitionKey": "string", // Optional: Partition key
|
|
117
|
-
"forkedFrom": "string", // Optional: Parent workflow ID
|
|
118
|
-
"ownerXid": "string | null", // Required: Transaction ID
|
|
119
|
-
"options": {
|
|
120
|
-
"isRecoveryRequest": false, // Optional
|
|
121
|
-
"isDequeuedRequest": false, // Optional
|
|
122
|
-
"maxRetries": 100 // Optional
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
**Response 200/201:**
|
|
128
|
-
|
|
129
|
-
```json
|
|
130
|
-
{
|
|
131
|
-
"status": "PENDING", // Current status after creation
|
|
132
|
-
"shouldExecuteOnThisExecutor": true, // Whether this executor should run it
|
|
133
|
-
"deadlineEpochMS": 1234567890 // Optional: Calculated deadline
|
|
134
|
-
}
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
**Atomicity**: This endpoint must be atomic. If a workflow with the same UUID exists:
|
|
138
|
-
|
|
139
|
-
- Return `shouldExecuteOnThisExecutor: false` if another executor is handling it
|
|
140
|
-
- Return 409 if there's a true conflict
|
|
141
|
-
|
|
142
|
-
---
|
|
143
|
-
|
|
144
|
-
### Get Workflow Status
|
|
145
|
-
|
|
146
|
-
#### GET /workflows/{workflowID}
|
|
147
|
-
|
|
148
|
-
Retrieve workflow status.
|
|
149
|
-
|
|
150
|
-
**Path Parameters:**
|
|
151
|
-
|
|
152
|
-
- `workflowID` (string, URL-encoded): Workflow UUID
|
|
153
|
-
|
|
154
|
-
**Query Parameters:**
|
|
155
|
-
|
|
156
|
-
- `callerID` (string, optional): Calling workflow's ID
|
|
157
|
-
- `callerFN` (number, optional): Calling workflow's function ID
|
|
158
|
-
|
|
159
|
-
**Response 200:**
|
|
160
|
-
|
|
161
|
-
```json
|
|
162
|
-
{
|
|
163
|
-
"workflowUUID": "string",
|
|
164
|
-
"status": "PENDING | SUCCESS | ERROR | CANCELLED | ENQUEUED | MAX_RECOVERY_ATTEMPTS_EXCEEDED",
|
|
165
|
-
"workflowName": "string",
|
|
166
|
-
"workflowClassName": "string",
|
|
167
|
-
"workflowConfigName": "string",
|
|
168
|
-
"queueName": "string | null",
|
|
169
|
-
"authenticatedUser": "string",
|
|
170
|
-
"assumedRole": "string",
|
|
171
|
-
"authenticatedRoles": ["string"],
|
|
172
|
-
"request": {},
|
|
173
|
-
"executorId": "string",
|
|
174
|
-
"applicationVersion": "string",
|
|
175
|
-
"applicationID": "string",
|
|
176
|
-
"input": "string | null", // Serialized JSON
|
|
177
|
-
"output": "string | null", // Serialized JSON
|
|
178
|
-
"error": "string | null", // Serialized error
|
|
179
|
-
"createdAt": 1234567890,
|
|
180
|
-
"updatedAt": 1234567890,
|
|
181
|
-
"recoveryAttempts": 0,
|
|
182
|
-
"timeoutMS": 30000,
|
|
183
|
-
"deadlineEpochMS": 1234567890,
|
|
184
|
-
"deduplicationID": "string",
|
|
185
|
-
"priority": 0,
|
|
186
|
-
"queuePartitionKey": "string",
|
|
187
|
-
"forkedFrom": "string"
|
|
188
|
-
}
|
|
189
|
-
```
|
|
190
|
-
|
|
191
|
-
**Response 404** (workflow not found):
|
|
192
|
-
|
|
193
|
-
```json
|
|
194
|
-
{
|
|
195
|
-
"message": "Workflow not found",
|
|
196
|
-
"type": "workflow_not_found"
|
|
197
|
-
}
|
|
198
|
-
```
|
|
199
|
-
|
|
200
|
-
---
|
|
201
|
-
|
|
202
|
-
### List Workflows
|
|
203
|
-
|
|
204
|
-
#### GET /workflows
|
|
205
|
-
|
|
206
|
-
List workflows with optional filters.
|
|
207
|
-
|
|
208
|
-
**Query Parameters:**
|
|
209
|
-
|
|
210
|
-
- `workflowName` (string): Filter by workflow name
|
|
211
|
-
- `authenticatedUser` (string): Filter by user
|
|
212
|
-
- `startTime` (string): RFC 3339 timestamp, workflows created after
|
|
213
|
-
- `endTime` (string): RFC 3339 timestamp, workflows created before
|
|
214
|
-
- `status` (string): Filter by status
|
|
215
|
-
- `applicationVersion` (string): Filter by app version
|
|
216
|
-
- `workflowID` (string): Filter by workflow ID (exact or prefix match)
|
|
217
|
-
- `limit` (number): Max results (default: 100)
|
|
218
|
-
- `offset` (number): Pagination offset
|
|
219
|
-
- `sortAscending` (boolean): Sort order (default: false = descending)
|
|
220
|
-
|
|
221
|
-
**Response 200:**
|
|
222
|
-
|
|
223
|
-
```json
|
|
224
|
-
[
|
|
225
|
-
{
|
|
226
|
-
"workflowUUID": "string",
|
|
227
|
-
"status": "string"
|
|
228
|
-
// ... full WorkflowStatusInternal object
|
|
229
|
-
}
|
|
230
|
-
]
|
|
231
|
-
```
|
|
232
|
-
|
|
233
|
-
---
|
|
234
|
-
|
|
235
|
-
### Record Workflow Output
|
|
236
|
-
|
|
237
|
-
#### PUT /workflows/{workflowID}/output
|
|
238
|
-
|
|
239
|
-
Record successful workflow completion.
|
|
240
|
-
|
|
241
|
-
**Path Parameters:**
|
|
242
|
-
|
|
243
|
-
- `workflowID` (string): Workflow UUID
|
|
244
|
-
|
|
245
|
-
**Request Body:**
|
|
246
|
-
|
|
247
|
-
```json
|
|
248
|
-
{
|
|
249
|
-
"output": "string", // Serialized JSON output
|
|
250
|
-
"status": "SUCCESS" // New status
|
|
251
|
-
}
|
|
252
|
-
```
|
|
253
|
-
|
|
254
|
-
**Response 200:**
|
|
255
|
-
|
|
256
|
-
```json
|
|
257
|
-
{}
|
|
258
|
-
```
|
|
259
|
-
|
|
260
|
-
---
|
|
261
|
-
|
|
262
|
-
### Record Workflow Error
|
|
263
|
-
|
|
264
|
-
#### PUT /workflows/{workflowID}/error
|
|
265
|
-
|
|
266
|
-
Record workflow failure.
|
|
267
|
-
|
|
268
|
-
**Path Parameters:**
|
|
269
|
-
|
|
270
|
-
- `workflowID` (string): Workflow UUID
|
|
271
|
-
|
|
272
|
-
**Request Body:**
|
|
273
|
-
|
|
274
|
-
```json
|
|
275
|
-
{
|
|
276
|
-
"error": "string", // Serialized error
|
|
277
|
-
"status": "ERROR" // New status
|
|
278
|
-
}
|
|
279
|
-
```
|
|
280
|
-
|
|
281
|
-
**Response 200:**
|
|
282
|
-
|
|
283
|
-
```json
|
|
284
|
-
{}
|
|
285
|
-
```
|
|
286
|
-
|
|
287
|
-
---
|
|
288
|
-
|
|
289
|
-
### Get Workflow Result (Polling)
|
|
290
|
-
|
|
291
|
-
#### GET /workflows/{workflowID}/result
|
|
292
|
-
|
|
293
|
-
Get workflow result for polling. SDK polls this endpoint until workflow completes.
|
|
294
|
-
|
|
295
|
-
**Path Parameters:**
|
|
296
|
-
|
|
297
|
-
- `workflowID` (string): Workflow UUID
|
|
298
|
-
|
|
299
|
-
**Query Parameters:**
|
|
300
|
-
|
|
301
|
-
- `callerID` (string, optional): Calling workflow's ID
|
|
302
|
-
- `timerFuncID` (number, optional): Timer function ID
|
|
303
|
-
|
|
304
|
-
**Response 200** (workflow complete):
|
|
305
|
-
|
|
306
|
-
```json
|
|
307
|
-
{
|
|
308
|
-
"output": "string | null", // Serialized output
|
|
309
|
-
"error": "string | null", // Serialized error
|
|
310
|
-
"cancelled": false
|
|
311
|
-
}
|
|
312
|
-
```
|
|
313
|
-
|
|
314
|
-
**Response 200** (workflow still pending):
|
|
315
|
-
|
|
316
|
-
```json
|
|
317
|
-
null
|
|
318
|
-
```
|
|
319
|
-
|
|
320
|
-
**Polling**: SDK polls every 1000ms. Consider implementing long-polling or returning immediately if result is ready.
|
|
321
|
-
|
|
322
|
-
---
|
|
323
|
-
|
|
324
|
-
### Get Pending Workflows
|
|
325
|
-
|
|
326
|
-
#### GET /workflows/pending
|
|
327
|
-
|
|
328
|
-
Get workflows that need recovery.
|
|
329
|
-
|
|
330
|
-
**Query Parameters:**
|
|
331
|
-
|
|
332
|
-
- `executorId` (string, required): Executor ID
|
|
333
|
-
- `appVersion` (string, required): Application version
|
|
334
|
-
|
|
335
|
-
**Response 200:**
|
|
336
|
-
|
|
337
|
-
```json
|
|
338
|
-
[
|
|
339
|
-
{
|
|
340
|
-
"workflowUUID": "string",
|
|
341
|
-
"queueName": "string | null"
|
|
342
|
-
}
|
|
343
|
-
]
|
|
344
|
-
```
|
|
345
|
-
|
|
346
|
-
---
|
|
347
|
-
|
|
348
|
-
### Set Workflow Status
|
|
349
|
-
|
|
350
|
-
#### PUT /workflows/{workflowID}/status
|
|
351
|
-
|
|
352
|
-
Update workflow status.
|
|
353
|
-
|
|
354
|
-
**Path Parameters:**
|
|
355
|
-
|
|
356
|
-
- `workflowID` (string): Workflow UUID
|
|
357
|
-
|
|
358
|
-
**Request Body:**
|
|
359
|
-
|
|
360
|
-
```json
|
|
361
|
-
{
|
|
362
|
-
"status": "PENDING | SUCCESS | ERROR | CANCELLED | ENQUEUED | MAX_RECOVERY_ATTEMPTS_EXCEEDED",
|
|
363
|
-
"resetRecoveryAttempts": false
|
|
364
|
-
}
|
|
365
|
-
```
|
|
366
|
-
|
|
367
|
-
**Response 200:**
|
|
368
|
-
|
|
369
|
-
```json
|
|
370
|
-
{}
|
|
371
|
-
```
|
|
372
|
-
|
|
373
|
-
---
|
|
374
|
-
|
|
375
|
-
### Cancel Workflow
|
|
376
|
-
|
|
377
|
-
#### POST /workflows/{workflowID}/cancel
|
|
378
|
-
|
|
379
|
-
Cancel a running workflow.
|
|
380
|
-
|
|
381
|
-
**Path Parameters:**
|
|
382
|
-
|
|
383
|
-
- `workflowID` (string): Workflow UUID
|
|
384
|
-
|
|
385
|
-
**Request Body:**
|
|
386
|
-
|
|
387
|
-
```json
|
|
388
|
-
{}
|
|
389
|
-
```
|
|
390
|
-
|
|
391
|
-
**Response 200:**
|
|
392
|
-
|
|
393
|
-
```json
|
|
394
|
-
{}
|
|
395
|
-
```
|
|
396
|
-
|
|
397
|
-
**Side Effects**: Must update workflow status to "CANCELLED" and notify any waiting operations.
|
|
398
|
-
|
|
399
|
-
---
|
|
400
|
-
|
|
401
|
-
### Resume Workflow
|
|
402
|
-
|
|
403
|
-
#### POST /workflows/{workflowID}/resume
|
|
404
|
-
|
|
405
|
-
Resume a cancelled workflow.
|
|
406
|
-
|
|
407
|
-
**Path Parameters:**
|
|
408
|
-
|
|
409
|
-
- `workflowID` (string): Workflow UUID
|
|
410
|
-
|
|
411
|
-
**Request Body:**
|
|
412
|
-
|
|
413
|
-
```json
|
|
414
|
-
{}
|
|
415
|
-
```
|
|
416
|
-
|
|
417
|
-
**Response 200:**
|
|
418
|
-
|
|
419
|
-
```json
|
|
420
|
-
{}
|
|
421
|
-
```
|
|
422
|
-
|
|
423
|
-
---
|
|
424
|
-
|
|
425
|
-
### Fork Workflow
|
|
426
|
-
|
|
427
|
-
#### POST /workflows/{workflowID}/fork
|
|
428
|
-
|
|
429
|
-
Create a new workflow from an existing one, starting at a specific step.
|
|
430
|
-
|
|
431
|
-
**Path Parameters:**
|
|
432
|
-
|
|
433
|
-
- `workflowID` (string): Source workflow UUID
|
|
434
|
-
|
|
435
|
-
**Request Body:**
|
|
436
|
-
|
|
437
|
-
```json
|
|
438
|
-
{
|
|
439
|
-
"startStep": 0, // Step number to start from
|
|
440
|
-
"newWorkflowID": "string", // Optional: New workflow ID
|
|
441
|
-
"applicationVersion": "string", // Optional: App version
|
|
442
|
-
"timeoutMS": 30000 // Optional: New timeout
|
|
443
|
-
}
|
|
444
|
-
```
|
|
445
|
-
|
|
446
|
-
**Response 200:**
|
|
447
|
-
|
|
448
|
-
```json
|
|
449
|
-
{
|
|
450
|
-
"newWorkflowID": "string"
|
|
451
|
-
}
|
|
452
|
-
```
|
|
453
|
-
|
|
454
|
-
---
|
|
455
|
-
|
|
456
|
-
### Check If Cancelled
|
|
457
|
-
|
|
458
|
-
#### GET /workflows/{workflowID}/cancelled
|
|
459
|
-
|
|
460
|
-
Check if workflow has been cancelled.
|
|
461
|
-
|
|
462
|
-
**Path Parameters:**
|
|
463
|
-
|
|
464
|
-
- `workflowID` (string): Workflow UUID
|
|
465
|
-
|
|
466
|
-
**Response 200:**
|
|
467
|
-
|
|
468
|
-
```json
|
|
469
|
-
{
|
|
470
|
-
"cancelled": true | false
|
|
471
|
-
}
|
|
472
|
-
```
|
|
473
|
-
|
|
474
|
-
---
|
|
475
|
-
|
|
476
|
-
## Operation Endpoints
|
|
477
|
-
|
|
478
|
-
Operations are individual steps within a workflow.
|
|
479
|
-
|
|
480
|
-
### Get Operation Result
|
|
481
|
-
|
|
482
|
-
#### GET /workflows/{workflowID}/operations/{functionID}
|
|
483
|
-
|
|
484
|
-
Get a specific operation's result.
|
|
485
|
-
|
|
486
|
-
**Path Parameters:**
|
|
487
|
-
|
|
488
|
-
- `workflowID` (string): Workflow UUID
|
|
489
|
-
- `functionID` (number): Function/step ID
|
|
490
|
-
|
|
491
|
-
**Response 200** (operation exists):
|
|
492
|
-
|
|
493
|
-
```json
|
|
494
|
-
{
|
|
495
|
-
"output": "string | null", // Serialized output
|
|
496
|
-
"error": "string | null", // Serialized error
|
|
497
|
-
"cancelled": false,
|
|
498
|
-
"childWorkflowID": "string | null",
|
|
499
|
-
"functionName": "string"
|
|
500
|
-
}
|
|
501
|
-
```
|
|
502
|
-
|
|
503
|
-
**Response 200** (operation not recorded yet):
|
|
504
|
-
|
|
505
|
-
```json
|
|
506
|
-
null
|
|
507
|
-
```
|
|
508
|
-
|
|
509
|
-
---
|
|
510
|
-
|
|
511
|
-
### Get All Operation Results
|
|
512
|
-
|
|
513
|
-
#### GET /workflows/{workflowID}/operations
|
|
514
|
-
|
|
515
|
-
Get all operations for a workflow.
|
|
516
|
-
|
|
517
|
-
**Path Parameters:**
|
|
518
|
-
|
|
519
|
-
- `workflowID` (string): Workflow UUID
|
|
520
|
-
|
|
521
|
-
**Response 200:**
|
|
522
|
-
|
|
523
|
-
```json
|
|
524
|
-
[
|
|
525
|
-
{
|
|
526
|
-
"workflow_uuid": "string",
|
|
527
|
-
"function_id": 0,
|
|
528
|
-
"output": "string",
|
|
529
|
-
"error": "string",
|
|
530
|
-
"child_workflow_id": "string",
|
|
531
|
-
"function_name": "string",
|
|
532
|
-
"started_at_epoch_ms": 1234567890,
|
|
533
|
-
"completed_at_epoch_ms": 1234567890
|
|
534
|
-
}
|
|
535
|
-
]
|
|
536
|
-
```
|
|
537
|
-
|
|
538
|
-
---
|
|
539
|
-
|
|
540
|
-
### Record Operation Result
|
|
541
|
-
|
|
542
|
-
#### POST /workflows/{workflowID}/operations
|
|
543
|
-
|
|
544
|
-
Record an operation's completion.
|
|
545
|
-
|
|
546
|
-
**Path Parameters:**
|
|
547
|
-
|
|
548
|
-
- `workflowID` (string): Workflow UUID
|
|
549
|
-
|
|
550
|
-
**Request Body:**
|
|
551
|
-
|
|
552
|
-
```json
|
|
553
|
-
{
|
|
554
|
-
"functionID": 0, // Required: Step number
|
|
555
|
-
"functionName": "string", // Required: Function name
|
|
556
|
-
"checkConflict": true, // Required: Check for existing record
|
|
557
|
-
"startTimeEpochMs": 1234567890, // Required: When operation started
|
|
558
|
-
"endTimeEpochMs": 1234567890, // Required: When operation ended
|
|
559
|
-
"output": "string | null", // Optional: Serialized output
|
|
560
|
-
"error": "string | null", // Optional: Serialized error
|
|
561
|
-
"childWorkflowID": "string | null" // Optional: If operation started a child workflow
|
|
562
|
-
}
|
|
563
|
-
```
|
|
564
|
-
|
|
565
|
-
**Response 200:**
|
|
566
|
-
|
|
567
|
-
```json
|
|
568
|
-
{}
|
|
569
|
-
```
|
|
570
|
-
|
|
571
|
-
**Atomicity**: If `checkConflict` is true and a record exists, return 409.
|
|
572
|
-
|
|
573
|
-
---
|
|
574
|
-
|
|
575
|
-
## Queue Endpoints
|
|
576
|
-
|
|
577
|
-
### Clear Queue Assignment
|
|
578
|
-
|
|
579
|
-
#### DELETE /workflows/{workflowID}/queue-assignment
|
|
580
|
-
|
|
581
|
-
Remove a workflow from its queue assignment.
|
|
582
|
-
|
|
583
|
-
**Path Parameters:**
|
|
584
|
-
|
|
585
|
-
- `workflowID` (string): Workflow UUID
|
|
586
|
-
|
|
587
|
-
**Response 200:**
|
|
588
|
-
|
|
589
|
-
```json
|
|
590
|
-
{
|
|
591
|
-
"cleared": true
|
|
592
|
-
}
|
|
593
|
-
```
|
|
594
|
-
|
|
595
|
-
---
|
|
596
|
-
|
|
597
|
-
### Get Deduplicated Workflow
|
|
598
|
-
|
|
599
|
-
#### GET /queues/{queueName}/deduplicated/{deduplicationID}
|
|
600
|
-
|
|
601
|
-
Find workflow by deduplication ID.
|
|
602
|
-
|
|
603
|
-
**Path Parameters:**
|
|
604
|
-
|
|
605
|
-
- `queueName` (string): Queue name
|
|
606
|
-
- `deduplicationID` (string): Deduplication ID
|
|
607
|
-
|
|
608
|
-
**Response 200:**
|
|
609
|
-
|
|
610
|
-
```json
|
|
611
|
-
{
|
|
612
|
-
"workflowID": "string | null" // null if no match
|
|
613
|
-
}
|
|
614
|
-
```
|
|
615
|
-
|
|
616
|
-
---
|
|
617
|
-
|
|
618
|
-
### Get Queue Partitions
|
|
619
|
-
|
|
620
|
-
#### GET /queues/{queueName}/partitions
|
|
621
|
-
|
|
622
|
-
Get all partition keys for a queue.
|
|
623
|
-
|
|
624
|
-
**Path Parameters:**
|
|
625
|
-
|
|
626
|
-
- `queueName` (string): Queue name
|
|
627
|
-
|
|
628
|
-
**Response 200:**
|
|
629
|
-
|
|
630
|
-
```json
|
|
631
|
-
{
|
|
632
|
-
"partitions": ["string"]
|
|
633
|
-
}
|
|
634
|
-
```
|
|
635
|
-
|
|
636
|
-
---
|
|
637
|
-
|
|
638
|
-
### Find and Mark Startable Workflows
|
|
639
|
-
|
|
640
|
-
#### POST /queues/{queueName}/start-workflows
|
|
641
|
-
|
|
642
|
-
Find workflows ready to start and mark them as starting.
|
|
643
|
-
|
|
644
|
-
**Path Parameters:**
|
|
645
|
-
|
|
646
|
-
- `queueName` (string): Queue name
|
|
647
|
-
|
|
648
|
-
**Request Body:**
|
|
649
|
-
|
|
650
|
-
```json
|
|
651
|
-
{
|
|
652
|
-
"executorID": "string", // Required
|
|
653
|
-
"appVersion": "string", // Required
|
|
654
|
-
"queuePartitionKey": "string | null", // Optional
|
|
655
|
-
"concurrency": 10, // Required: Max concurrent workflows
|
|
656
|
-
"rateLimit": {
|
|
657
|
-
// Optional: Rate limiting config
|
|
658
|
-
"limitPerPeriod": 100,
|
|
659
|
-
"periodSec": 60
|
|
660
|
-
}
|
|
661
|
-
}
|
|
662
|
-
```
|
|
663
|
-
|
|
664
|
-
**Response 200:**
|
|
665
|
-
|
|
666
|
-
```json
|
|
667
|
-
{
|
|
668
|
-
"workflowIDs": ["string"] // Workflows that should be started
|
|
669
|
-
}
|
|
670
|
-
```
|
|
671
|
-
|
|
672
|
-
**Atomicity**: This operation MUST be atomic (use transactions). It should:
|
|
673
|
-
|
|
674
|
-
1. Find eligible workflows (ENQUEUED status, respecting concurrency/rate limits)
|
|
675
|
-
2. Update their status to PENDING
|
|
676
|
-
3. Return their IDs
|
|
677
|
-
|
|
678
|
-
---
|
|
679
|
-
|
|
680
|
-
## Messaging Endpoints
|
|
681
|
-
|
|
682
|
-
### Send Message
|
|
683
|
-
|
|
684
|
-
#### POST /workflows/{destinationID}/messages
|
|
685
|
-
|
|
686
|
-
Send a message to a workflow.
|
|
687
|
-
|
|
688
|
-
**Path Parameters:**
|
|
689
|
-
|
|
690
|
-
- `destinationID` (string): Destination workflow UUID
|
|
691
|
-
|
|
692
|
-
**Request Body:**
|
|
693
|
-
|
|
694
|
-
```json
|
|
695
|
-
{
|
|
696
|
-
"senderWorkflowID": "string", // Required: Sender's workflow ID
|
|
697
|
-
"functionID": 0, // Required: Sender's function ID
|
|
698
|
-
"message": "string | null", // Required: Message content (serialized)
|
|
699
|
-
"topic": "string" // Optional: Message topic
|
|
700
|
-
}
|
|
701
|
-
```
|
|
702
|
-
|
|
703
|
-
**Response 200:**
|
|
704
|
-
|
|
705
|
-
```json
|
|
706
|
-
{}
|
|
707
|
-
```
|
|
708
|
-
|
|
709
|
-
**Side Effects**: Must wake up any `recv` polling for this destination+topic.
|
|
710
|
-
|
|
711
|
-
---
|
|
712
|
-
|
|
713
|
-
### Receive Message (Polling)
|
|
714
|
-
|
|
715
|
-
#### GET /workflows/{workflowID}/messages
|
|
716
|
-
|
|
717
|
-
Check for messages. SDK polls this endpoint.
|
|
718
|
-
|
|
719
|
-
**Path Parameters:**
|
|
720
|
-
|
|
721
|
-
- `workflowID` (string): Workflow UUID
|
|
722
|
-
|
|
723
|
-
**Query Parameters:**
|
|
724
|
-
|
|
725
|
-
- `topic` (string, optional): Filter by topic
|
|
726
|
-
- `functionID` (number, required): Receiver's function ID
|
|
727
|
-
- `timeoutFunctionID` (number, required): Timeout function ID
|
|
728
|
-
|
|
729
|
-
**Response 200** (message available):
|
|
730
|
-
|
|
731
|
-
```json
|
|
732
|
-
{
|
|
733
|
-
"message": "string | null",
|
|
734
|
-
"found": true
|
|
735
|
-
}
|
|
736
|
-
```
|
|
737
|
-
|
|
738
|
-
**Response 200** (no message yet):
|
|
739
|
-
|
|
740
|
-
```json
|
|
741
|
-
{
|
|
742
|
-
"message": null,
|
|
743
|
-
"found": false
|
|
744
|
-
}
|
|
745
|
-
```
|
|
746
|
-
|
|
747
|
-
**Polling**: SDK polls every 1000ms with timeout. Consider long-polling.
|
|
748
|
-
|
|
749
|
-
---
|
|
750
|
-
|
|
751
|
-
### Durable Sleep
|
|
752
|
-
|
|
753
|
-
#### POST /workflows/{workflowID}/sleep
|
|
754
|
-
|
|
755
|
-
Record a durable sleep operation.
|
|
756
|
-
|
|
757
|
-
**Path Parameters:**
|
|
758
|
-
|
|
759
|
-
- `workflowID` (string): Workflow UUID
|
|
760
|
-
|
|
761
|
-
**Request Body:**
|
|
762
|
-
|
|
763
|
-
```json
|
|
764
|
-
{
|
|
765
|
-
"functionID": 0, // Required: Function ID
|
|
766
|
-
"duration": 5000, // Required: Sleep duration ms
|
|
767
|
-
"wakeupTime": 1234567890 // Required: Wakeup timestamp ms
|
|
768
|
-
}
|
|
769
|
-
```
|
|
770
|
-
|
|
771
|
-
**Response 200:**
|
|
772
|
-
|
|
773
|
-
```json
|
|
774
|
-
{}
|
|
775
|
-
```
|
|
776
|
-
|
|
777
|
-
---
|
|
778
|
-
|
|
779
|
-
## Event Endpoints
|
|
780
|
-
|
|
781
|
-
### Set Event
|
|
782
|
-
|
|
783
|
-
#### PUT /workflows/{workflowID}/events/{key}
|
|
784
|
-
|
|
785
|
-
Set an event value.
|
|
786
|
-
|
|
787
|
-
**Path Parameters:**
|
|
788
|
-
|
|
789
|
-
- `workflowID` (string): Workflow UUID
|
|
790
|
-
- `key` (string): Event key
|
|
791
|
-
|
|
792
|
-
**Request Body:**
|
|
793
|
-
|
|
794
|
-
```json
|
|
795
|
-
{
|
|
796
|
-
"functionID": 0, // Required
|
|
797
|
-
"value": "string | null" // Required: Serialized value
|
|
798
|
-
}
|
|
799
|
-
```
|
|
800
|
-
|
|
801
|
-
**Response 200:**
|
|
802
|
-
|
|
803
|
-
```json
|
|
804
|
-
{}
|
|
805
|
-
```
|
|
806
|
-
|
|
807
|
-
**Side Effects**: Must wake up any `getEvent` polling for this workflow+key.
|
|
808
|
-
|
|
809
|
-
---
|
|
810
|
-
|
|
811
|
-
### Get Event (Polling)
|
|
812
|
-
|
|
813
|
-
#### GET /workflows/{workflowID}/events/{key}
|
|
814
|
-
|
|
815
|
-
Get an event value. SDK polls this endpoint.
|
|
816
|
-
|
|
817
|
-
**Path Parameters:**
|
|
818
|
-
|
|
819
|
-
- `workflowID` (string): Workflow UUID
|
|
820
|
-
- `key` (string): Event key
|
|
821
|
-
|
|
822
|
-
**Query Parameters:**
|
|
823
|
-
|
|
824
|
-
- `callerWorkflowID` (string, optional): Caller's workflow ID
|
|
825
|
-
- `callerFunctionID` (number, optional): Caller's function ID
|
|
826
|
-
- `callerTimeoutFunctionID` (number, optional): Caller's timeout function ID
|
|
827
|
-
|
|
828
|
-
**Response 200** (event set):
|
|
829
|
-
|
|
830
|
-
```json
|
|
831
|
-
{
|
|
832
|
-
"value": "string | null",
|
|
833
|
-
"found": true
|
|
834
|
-
}
|
|
835
|
-
```
|
|
836
|
-
|
|
837
|
-
**Response 200** (event not set):
|
|
838
|
-
|
|
839
|
-
```json
|
|
840
|
-
{
|
|
841
|
-
"value": null,
|
|
842
|
-
"found": false
|
|
843
|
-
}
|
|
844
|
-
```
|
|
845
|
-
|
|
846
|
-
**Polling**: SDK polls every 1000ms with timeout. Consider long-polling.
|
|
847
|
-
|
|
848
|
-
---
|
|
849
|
-
|
|
850
|
-
## Event Dispatch Endpoints
|
|
851
|
-
|
|
852
|
-
### Get Event Dispatch State
|
|
853
|
-
|
|
854
|
-
#### GET /event-dispatch/{service}/{workflowFnName}/{key}
|
|
855
|
-
|
|
856
|
-
Get external event dispatch state.
|
|
857
|
-
|
|
858
|
-
**Path Parameters:**
|
|
859
|
-
|
|
860
|
-
- `service` (string): Service name
|
|
861
|
-
- `workflowFnName` (string): Workflow function name
|
|
862
|
-
- `key` (string): State key
|
|
863
|
-
|
|
864
|
-
**Response 200:**
|
|
865
|
-
|
|
866
|
-
```json
|
|
867
|
-
{
|
|
868
|
-
"service_name": "string",
|
|
869
|
-
"workflow_fn_name": "string",
|
|
870
|
-
"key": "string",
|
|
871
|
-
"value": "string",
|
|
872
|
-
"update_time": 1234567890,
|
|
873
|
-
"update_seq": 123
|
|
874
|
-
}
|
|
875
|
-
```
|
|
876
|
-
|
|
877
|
-
**Response 404** (not found):
|
|
878
|
-
|
|
879
|
-
```json
|
|
880
|
-
null
|
|
881
|
-
```
|
|
882
|
-
|
|
883
|
-
---
|
|
884
|
-
|
|
885
|
-
### Upsert Event Dispatch State
|
|
886
|
-
|
|
887
|
-
#### PUT /event-dispatch
|
|
888
|
-
|
|
889
|
-
Create or update event dispatch state.
|
|
890
|
-
|
|
891
|
-
**Request Body:**
|
|
892
|
-
|
|
893
|
-
```json
|
|
894
|
-
{
|
|
895
|
-
"service_name": "string", // Required
|
|
896
|
-
"workflow_fn_name": "string", // Required
|
|
897
|
-
"key": "string", // Required
|
|
898
|
-
"value": "string", // Optional
|
|
899
|
-
"update_time": 1234567890, // Optional
|
|
900
|
-
"update_seq": 123 // Optional
|
|
901
|
-
}
|
|
902
|
-
```
|
|
903
|
-
|
|
904
|
-
**Response 200:**
|
|
905
|
-
|
|
906
|
-
```json
|
|
907
|
-
{
|
|
908
|
-
"service_name": "string",
|
|
909
|
-
"workflow_fn_name": "string",
|
|
910
|
-
"key": "string",
|
|
911
|
-
"value": "string",
|
|
912
|
-
"update_time": 1234567890,
|
|
913
|
-
"update_seq": 123
|
|
914
|
-
}
|
|
915
|
-
```
|
|
916
|
-
|
|
917
|
-
**Atomicity**: Upsert must be atomic with optimistic locking on `update_seq`.
|
|
918
|
-
|
|
919
|
-
---
|
|
920
|
-
|
|
921
|
-
## Stream Endpoints
|
|
922
|
-
|
|
923
|
-
### Write to Stream
|
|
924
|
-
|
|
925
|
-
#### POST /workflows/{workflowID}/streams/{key}
|
|
926
|
-
|
|
927
|
-
Write a value to a stream.
|
|
928
|
-
|
|
929
|
-
**Path Parameters:**
|
|
930
|
-
|
|
931
|
-
- `workflowID` (string): Workflow UUID
|
|
932
|
-
- `key` (string): Stream key
|
|
933
|
-
|
|
934
|
-
**Request Body:**
|
|
935
|
-
|
|
936
|
-
```json
|
|
937
|
-
{
|
|
938
|
-
"fromWorkflow": true, // Required: true if from workflow, false if from step
|
|
939
|
-
"functionID": 0, // Required if fromWorkflow is true
|
|
940
|
-
"value": {} // Required: Value to write (any JSON)
|
|
941
|
-
}
|
|
942
|
-
```
|
|
943
|
-
|
|
944
|
-
**Response 200:**
|
|
945
|
-
|
|
946
|
-
```json
|
|
947
|
-
{}
|
|
948
|
-
```
|
|
949
|
-
|
|
950
|
-
---
|
|
951
|
-
|
|
952
|
-
### Close Stream
|
|
953
|
-
|
|
954
|
-
#### POST /workflows/{workflowID}/streams/{key}/close
|
|
955
|
-
|
|
956
|
-
Close a stream.
|
|
957
|
-
|
|
958
|
-
**Path Parameters:**
|
|
959
|
-
|
|
960
|
-
- `workflowID` (string): Workflow UUID
|
|
961
|
-
- `key` (string): Stream key
|
|
962
|
-
|
|
963
|
-
**Request Body:**
|
|
964
|
-
|
|
965
|
-
```json
|
|
966
|
-
{
|
|
967
|
-
"functionID": 0 // Required
|
|
968
|
-
}
|
|
969
|
-
```
|
|
970
|
-
|
|
971
|
-
**Response 200:**
|
|
972
|
-
|
|
973
|
-
```json
|
|
974
|
-
{}
|
|
975
|
-
```
|
|
976
|
-
|
|
977
|
-
---
|
|
978
|
-
|
|
979
|
-
### Read from Stream
|
|
980
|
-
|
|
981
|
-
#### GET /workflows/{workflowID}/streams/{key}/{offset}
|
|
982
|
-
|
|
983
|
-
Read from a stream at a specific offset.
|
|
984
|
-
|
|
985
|
-
**Path Parameters:**
|
|
986
|
-
|
|
987
|
-
- `workflowID` (string): Workflow UUID
|
|
988
|
-
- `key` (string): Stream key
|
|
989
|
-
- `offset` (number): Read offset
|
|
990
|
-
|
|
991
|
-
**Response 200:**
|
|
992
|
-
|
|
993
|
-
```json
|
|
994
|
-
{
|
|
995
|
-
"value": {}, // The value at this offset (any JSON)
|
|
996
|
-
"closed": false // Whether stream is closed
|
|
997
|
-
}
|
|
998
|
-
```
|
|
999
|
-
|
|
1000
|
-
If stream is closed and offset is past the end, return `closed: true`.
|
|
1001
|
-
|
|
1002
|
-
---
|
|
1003
|
-
|
|
1004
|
-
## Admin Endpoints
|
|
1005
|
-
|
|
1006
|
-
### Garbage Collect
|
|
1007
|
-
|
|
1008
|
-
#### POST /admin/garbage-collect
|
|
1009
|
-
|
|
1010
|
-
Clean up old workflow data.
|
|
1011
|
-
|
|
1012
|
-
**Request Body:**
|
|
1013
|
-
|
|
1014
|
-
```json
|
|
1015
|
-
{
|
|
1016
|
-
"cutoffEpochTimestampMs": 1234567890, // Optional: Delete before this time
|
|
1017
|
-
"rowsThreshold": 10000 // Optional: Max rows to keep
|
|
1018
|
-
}
|
|
1019
|
-
```
|
|
1020
|
-
|
|
1021
|
-
**Response 200:**
|
|
1022
|
-
|
|
1023
|
-
```json
|
|
1024
|
-
{}
|
|
1025
|
-
```
|
|
1026
|
-
|
|
1027
|
-
---
|
|
1028
|
-
|
|
1029
|
-
### Get Metrics
|
|
1030
|
-
|
|
1031
|
-
#### GET /admin/metrics
|
|
1032
|
-
|
|
1033
|
-
Get workflow metrics.
|
|
1034
|
-
|
|
1035
|
-
**Query Parameters:**
|
|
1036
|
-
|
|
1037
|
-
- `startTime` (string, required): RFC 3339 timestamp
|
|
1038
|
-
- `endTime` (string, required): RFC 3339 timestamp
|
|
1039
|
-
|
|
1040
|
-
**Response 200:**
|
|
1041
|
-
|
|
1042
|
-
```json
|
|
1043
|
-
[
|
|
1044
|
-
{
|
|
1045
|
-
"metricType": "string",
|
|
1046
|
-
"metricName": "string",
|
|
1047
|
-
"value": 123
|
|
1048
|
-
}
|
|
1049
|
-
]
|
|
1050
|
-
```
|
|
1051
|
-
|
|
1052
|
-
---
|
|
1053
|
-
|
|
1054
|
-
### Check Patch
|
|
1055
|
-
|
|
1056
|
-
#### GET /workflows/{workflowID}/patch/{functionID}
|
|
1057
|
-
|
|
1058
|
-
Check if a function has been patched.
|
|
1059
|
-
|
|
1060
|
-
**Path Parameters:**
|
|
1061
|
-
|
|
1062
|
-
- `workflowID` (string): Workflow UUID
|
|
1063
|
-
- `functionID` (number): Function ID
|
|
1064
|
-
|
|
1065
|
-
**Query Parameters:**
|
|
1066
|
-
|
|
1067
|
-
- `patchName` (string, required): Name of the patch
|
|
1068
|
-
- `deprecated` (boolean, required): Whether checking for deprecated patch
|
|
1069
|
-
|
|
1070
|
-
**Response 200:**
|
|
1071
|
-
|
|
1072
|
-
```json
|
|
1073
|
-
{
|
|
1074
|
-
"isPatched": false,
|
|
1075
|
-
"hasEntry": false
|
|
1076
|
-
}
|
|
1077
|
-
```
|
|
1078
|
-
|
|
1079
|
-
---
|
|
1080
|
-
|
|
1081
|
-
## Implementation Notes
|
|
1082
|
-
|
|
1083
|
-
### Atomicity Requirements
|
|
1084
|
-
|
|
1085
|
-
The following endpoints require atomic/transactional implementation:
|
|
1086
|
-
|
|
1087
|
-
1. **POST /workflows** - Conflict detection and status assignment must be atomic
|
|
1088
|
-
2. **POST /workflows/{id}/operations** - When `checkConflict` is true
|
|
1089
|
-
3. **POST /queues/{name}/start-workflows** - Finding and marking must be atomic
|
|
1090
|
-
4. **PUT /event-dispatch** - Optimistic locking on `update_seq`
|
|
1091
|
-
|
|
1092
|
-
### Polling Endpoints
|
|
1093
|
-
|
|
1094
|
-
These endpoints are polled by the SDK:
|
|
1095
|
-
|
|
1096
|
-
| Endpoint | Poll Interval | Notes |
|
|
1097
|
-
| -------------------------------- | ------------- | --------------------------------- |
|
|
1098
|
-
| GET /workflows/{id}/result | 1000ms | Until workflow completes |
|
|
1099
|
-
| GET /workflows/{id}/messages | 1000ms | Until message received or timeout |
|
|
1100
|
-
| GET /workflows/{id}/events/{key} | 1000ms | Until event set or timeout |
|
|
1101
|
-
|
|
1102
|
-
Consider implementing long-polling (hold connection until data available or timeout) to reduce request overhead.
|
|
1103
|
-
|
|
1104
|
-
### Serialization
|
|
1105
|
-
|
|
1106
|
-
All `input`, `output`, `error`, `value`, and `message` fields contain serialized JSON strings. The SDK uses `superjson` for serialization which supports:
|
|
1107
|
-
|
|
1108
|
-
- Date objects
|
|
1109
|
-
- BigInt
|
|
1110
|
-
- Map/Set
|
|
1111
|
-
- undefined
|
|
1112
|
-
- Regular expressions
|
|
1113
|
-
- Custom class instances (with registration)
|
|
1114
|
-
|
|
1115
|
-
The backend should store these as opaque strings and return them unchanged.
|
|
1116
|
-
|
|
1117
|
-
### Status Values
|
|
1118
|
-
|
|
1119
|
-
Valid workflow statuses:
|
|
1120
|
-
|
|
1121
|
-
- `PENDING` - Workflow is running
|
|
1122
|
-
- `SUCCESS` - Completed successfully
|
|
1123
|
-
- `ERROR` - Completed with error
|
|
1124
|
-
- `ENQUEUED` - Waiting in queue
|
|
1125
|
-
- `CANCELLED` - Cancelled by user
|
|
1126
|
-
- `MAX_RECOVERY_ATTEMPTS_EXCEEDED` - Failed after max retries
|
|
1127
|
-
|
|
1128
|
-
---
|
|
1129
|
-
|
|
1130
|
-
## Database Schema for Laravel
|
|
1131
|
-
|
|
1132
|
-
Laravel must implement the database tables that store workflow state. This section documents the required schema.
|
|
1133
|
-
|
|
1134
|
-
### Table: workflow_status
|
|
1135
|
-
|
|
1136
|
-
Primary table for workflow state.
|
|
1137
|
-
|
|
1138
|
-
```sql
|
|
1139
|
-
CREATE TABLE workflow_status (
|
|
1140
|
-
workflow_uuid VARCHAR(255) PRIMARY KEY,
|
|
1141
|
-
status VARCHAR(50) NOT NULL,
|
|
1142
|
-
name VARCHAR(255) NOT NULL, -- workflowName
|
|
1143
|
-
class_name VARCHAR(255), -- workflowClassName
|
|
1144
|
-
config_name VARCHAR(255), -- workflowConfigName
|
|
1145
|
-
authenticated_user VARCHAR(255) NOT NULL DEFAULT '',
|
|
1146
|
-
output TEXT, -- Serialized JSON
|
|
1147
|
-
error TEXT, -- Serialized error
|
|
1148
|
-
assumed_role VARCHAR(255) NOT NULL DEFAULT '',
|
|
1149
|
-
authenticated_roles TEXT NOT NULL DEFAULT '[]', -- Serialized JSON array
|
|
1150
|
-
request TEXT NOT NULL DEFAULT '{}', -- Serialized JSON object
|
|
1151
|
-
executor_id VARCHAR(255) NOT NULL,
|
|
1152
|
-
application_version VARCHAR(255),
|
|
1153
|
-
queue_name VARCHAR(255),
|
|
1154
|
-
created_at BIGINT NOT NULL, -- Unix timestamp ms
|
|
1155
|
-
updated_at BIGINT NOT NULL, -- Unix timestamp ms
|
|
1156
|
-
application_id VARCHAR(255) NOT NULL,
|
|
1157
|
-
recovery_attempts INT NOT NULL DEFAULT 0,
|
|
1158
|
-
workflow_timeout_ms BIGINT,
|
|
1159
|
-
workflow_deadline_epoch_ms BIGINT,
|
|
1160
|
-
inputs TEXT, -- Serialized JSON
|
|
1161
|
-
started_at_epoch_ms BIGINT,
|
|
1162
|
-
deduplication_id VARCHAR(255),
|
|
1163
|
-
priority INT NOT NULL DEFAULT 0,
|
|
1164
|
-
queue_partition_key VARCHAR(255),
|
|
1165
|
-
forked_from VARCHAR(255),
|
|
1166
|
-
owner_xid VARCHAR(255),
|
|
1167
|
-
|
|
1168
|
-
-- Indexes for common queries
|
|
1169
|
-
INDEX idx_status (status),
|
|
1170
|
-
INDEX idx_executor (executor_id),
|
|
1171
|
-
INDEX idx_created_at (created_at),
|
|
1172
|
-
INDEX idx_queue_name (queue_name),
|
|
1173
|
-
INDEX idx_deduplication (queue_name, deduplication_id),
|
|
1174
|
-
INDEX idx_pending_recovery (status, executor_id, application_version)
|
|
1175
|
-
);
|
|
1176
|
-
```
|
|
1177
|
-
|
|
1178
|
-
### Table: operation_outputs
|
|
1179
|
-
|
|
1180
|
-
Stores results of individual workflow steps/operations.
|
|
1181
|
-
|
|
1182
|
-
```sql
|
|
1183
|
-
CREATE TABLE operation_outputs (
|
|
1184
|
-
workflow_uuid VARCHAR(255) NOT NULL,
|
|
1185
|
-
function_id INT NOT NULL,
|
|
1186
|
-
output TEXT, -- Serialized JSON
|
|
1187
|
-
error TEXT, -- Serialized error
|
|
1188
|
-
child_workflow_id VARCHAR(255),
|
|
1189
|
-
function_name VARCHAR(255),
|
|
1190
|
-
started_at_epoch_ms BIGINT,
|
|
1191
|
-
completed_at_epoch_ms BIGINT,
|
|
1192
|
-
|
|
1193
|
-
PRIMARY KEY (workflow_uuid, function_id),
|
|
1194
|
-
FOREIGN KEY (workflow_uuid) REFERENCES workflow_status(workflow_uuid) ON DELETE CASCADE,
|
|
1195
|
-
INDEX idx_child_workflow (child_workflow_id)
|
|
1196
|
-
);
|
|
1197
|
-
```
|
|
1198
|
-
|
|
1199
|
-
### Table: notifications
|
|
1200
|
-
|
|
1201
|
-
Stores messages sent between workflows.
|
|
1202
|
-
|
|
1203
|
-
```sql
|
|
1204
|
-
CREATE TABLE notifications (
|
|
1205
|
-
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
|
1206
|
-
destination_uuid VARCHAR(255) NOT NULL,
|
|
1207
|
-
topic VARCHAR(255),
|
|
1208
|
-
message TEXT, -- Serialized JSON
|
|
1209
|
-
created_at BIGINT NOT NULL,
|
|
1210
|
-
consumed BOOLEAN NOT NULL DEFAULT FALSE,
|
|
1211
|
-
|
|
1212
|
-
INDEX idx_destination_topic (destination_uuid, topic, consumed),
|
|
1213
|
-
FOREIGN KEY (destination_uuid) REFERENCES workflow_status(workflow_uuid) ON DELETE CASCADE
|
|
1214
|
-
);
|
|
1215
|
-
```
|
|
1216
|
-
|
|
1217
|
-
### Table: workflow_events
|
|
1218
|
-
|
|
1219
|
-
Stores key-value events set by workflows.
|
|
1220
|
-
|
|
1221
|
-
```sql
|
|
1222
|
-
CREATE TABLE workflow_events (
|
|
1223
|
-
workflow_uuid VARCHAR(255) NOT NULL,
|
|
1224
|
-
key VARCHAR(255) NOT NULL,
|
|
1225
|
-
value TEXT, -- Serialized JSON
|
|
1226
|
-
|
|
1227
|
-
PRIMARY KEY (workflow_uuid, key),
|
|
1228
|
-
FOREIGN KEY (workflow_uuid) REFERENCES workflow_status(workflow_uuid) ON DELETE CASCADE
|
|
1229
|
-
);
|
|
1230
|
-
```
|
|
1231
|
-
|
|
1232
|
-
### Table: event_dispatch_kv
|
|
1233
|
-
|
|
1234
|
-
Stores external event dispatch state for idempotency.
|
|
1235
|
-
|
|
1236
|
-
```sql
|
|
1237
|
-
CREATE TABLE event_dispatch_kv (
|
|
1238
|
-
service_name VARCHAR(255) NOT NULL,
|
|
1239
|
-
workflow_fn_name VARCHAR(255) NOT NULL,
|
|
1240
|
-
key VARCHAR(255) NOT NULL,
|
|
1241
|
-
value TEXT, -- Serialized JSON
|
|
1242
|
-
update_time BIGINT,
|
|
1243
|
-
update_seq BIGINT,
|
|
1244
|
-
|
|
1245
|
-
PRIMARY KEY (service_name, workflow_fn_name, key),
|
|
1246
|
-
INDEX idx_update_seq (update_seq)
|
|
1247
|
-
);
|
|
1248
|
-
```
|
|
1249
|
-
|
|
1250
|
-
### Table: workflow_streams
|
|
1251
|
-
|
|
1252
|
-
Stores stream data for workflow streaming.
|
|
1253
|
-
|
|
1254
|
-
```sql
|
|
1255
|
-
CREATE TABLE workflow_streams (
|
|
1256
|
-
workflow_uuid VARCHAR(255) NOT NULL,
|
|
1257
|
-
key VARCHAR(255) NOT NULL,
|
|
1258
|
-
offset INT NOT NULL,
|
|
1259
|
-
value TEXT NOT NULL, -- Serialized JSON
|
|
1260
|
-
is_closed BOOLEAN NOT NULL DEFAULT FALSE,
|
|
1261
|
-
|
|
1262
|
-
PRIMARY KEY (workflow_uuid, key, offset),
|
|
1263
|
-
FOREIGN KEY (workflow_uuid) REFERENCES workflow_status(workflow_uuid) ON DELETE CASCADE
|
|
1264
|
-
);
|
|
1265
|
-
```
|
|
1266
|
-
|
|
1267
|
-
### Table: workflow_queue_state (Optional)
|
|
1268
|
-
|
|
1269
|
-
For tracking queue concurrency and rate limiting. Can be managed in-memory if preferred.
|
|
1270
|
-
|
|
1271
|
-
```sql
|
|
1272
|
-
CREATE TABLE workflow_queue_state (
|
|
1273
|
-
queue_name VARCHAR(255) NOT NULL,
|
|
1274
|
-
partition_key VARCHAR(255) NOT NULL DEFAULT '',
|
|
1275
|
-
running_count INT NOT NULL DEFAULT 0,
|
|
1276
|
-
last_started_at BIGINT,
|
|
1277
|
-
|
|
1278
|
-
PRIMARY KEY (queue_name, partition_key)
|
|
1279
|
-
);
|
|
1280
|
-
```
|
|
1281
|
-
|
|
1282
|
-
### Laravel Migration Example
|
|
1283
|
-
|
|
1284
|
-
```php
|
|
1285
|
-
<?php
|
|
1286
|
-
|
|
1287
|
-
use Illuminate\Database\Migrations\Migration;
|
|
1288
|
-
use Illuminate\Database\Schema\Blueprint;
|
|
1289
|
-
use Illuminate\Support\Facades\Schema;
|
|
1290
|
-
|
|
1291
|
-
return new class extends Migration
|
|
1292
|
-
{
|
|
1293
|
-
public function up(): void
|
|
1294
|
-
{
|
|
1295
|
-
Schema::create('workflow_status', function (Blueprint $table) {
|
|
1296
|
-
$table->string('workflow_uuid')->primary();
|
|
1297
|
-
$table->string('status', 50);
|
|
1298
|
-
$table->string('name');
|
|
1299
|
-
$table->string('class_name')->nullable();
|
|
1300
|
-
$table->string('config_name')->nullable();
|
|
1301
|
-
$table->string('authenticated_user')->default('');
|
|
1302
|
-
$table->text('output')->nullable();
|
|
1303
|
-
$table->text('error')->nullable();
|
|
1304
|
-
$table->string('assumed_role')->default('');
|
|
1305
|
-
$table->text('authenticated_roles')->default('[]');
|
|
1306
|
-
$table->text('request')->default('{}');
|
|
1307
|
-
$table->string('executor_id');
|
|
1308
|
-
$table->string('application_version')->nullable();
|
|
1309
|
-
$table->string('queue_name')->nullable();
|
|
1310
|
-
$table->bigInteger('created_at');
|
|
1311
|
-
$table->bigInteger('updated_at');
|
|
1312
|
-
$table->string('application_id');
|
|
1313
|
-
$table->integer('recovery_attempts')->default(0);
|
|
1314
|
-
$table->bigInteger('workflow_timeout_ms')->nullable();
|
|
1315
|
-
$table->bigInteger('workflow_deadline_epoch_ms')->nullable();
|
|
1316
|
-
$table->text('inputs')->nullable();
|
|
1317
|
-
$table->bigInteger('started_at_epoch_ms')->nullable();
|
|
1318
|
-
$table->string('deduplication_id')->nullable();
|
|
1319
|
-
$table->integer('priority')->default(0);
|
|
1320
|
-
$table->string('queue_partition_key')->nullable();
|
|
1321
|
-
$table->string('forked_from')->nullable();
|
|
1322
|
-
$table->string('owner_xid')->nullable();
|
|
1323
|
-
|
|
1324
|
-
$table->index('status');
|
|
1325
|
-
$table->index('executor_id');
|
|
1326
|
-
$table->index('created_at');
|
|
1327
|
-
$table->index('queue_name');
|
|
1328
|
-
$table->index(['queue_name', 'deduplication_id']);
|
|
1329
|
-
$table->index(['status', 'executor_id', 'application_version']);
|
|
1330
|
-
});
|
|
1331
|
-
|
|
1332
|
-
Schema::create('operation_outputs', function (Blueprint $table) {
|
|
1333
|
-
$table->string('workflow_uuid');
|
|
1334
|
-
$table->integer('function_id');
|
|
1335
|
-
$table->text('output')->nullable();
|
|
1336
|
-
$table->text('error')->nullable();
|
|
1337
|
-
$table->string('child_workflow_id')->nullable();
|
|
1338
|
-
$table->string('function_name')->nullable();
|
|
1339
|
-
$table->bigInteger('started_at_epoch_ms')->nullable();
|
|
1340
|
-
$table->bigInteger('completed_at_epoch_ms')->nullable();
|
|
1341
|
-
|
|
1342
|
-
$table->primary(['workflow_uuid', 'function_id']);
|
|
1343
|
-
$table->foreign('workflow_uuid')
|
|
1344
|
-
->references('workflow_uuid')
|
|
1345
|
-
->on('workflow_status')
|
|
1346
|
-
->onDelete('cascade');
|
|
1347
|
-
$table->index('child_workflow_id');
|
|
1348
|
-
});
|
|
1349
|
-
|
|
1350
|
-
Schema::create('notifications', function (Blueprint $table) {
|
|
1351
|
-
$table->id();
|
|
1352
|
-
$table->string('destination_uuid');
|
|
1353
|
-
$table->string('topic')->nullable();
|
|
1354
|
-
$table->text('message')->nullable();
|
|
1355
|
-
$table->bigInteger('created_at');
|
|
1356
|
-
$table->boolean('consumed')->default(false);
|
|
1357
|
-
|
|
1358
|
-
$table->index(['destination_uuid', 'topic', 'consumed']);
|
|
1359
|
-
$table->foreign('destination_uuid')
|
|
1360
|
-
->references('workflow_uuid')
|
|
1361
|
-
->on('workflow_status')
|
|
1362
|
-
->onDelete('cascade');
|
|
1363
|
-
});
|
|
1364
|
-
|
|
1365
|
-
Schema::create('workflow_events', function (Blueprint $table) {
|
|
1366
|
-
$table->string('workflow_uuid');
|
|
1367
|
-
$table->string('key');
|
|
1368
|
-
$table->text('value')->nullable();
|
|
1369
|
-
|
|
1370
|
-
$table->primary(['workflow_uuid', 'key']);
|
|
1371
|
-
$table->foreign('workflow_uuid')
|
|
1372
|
-
->references('workflow_uuid')
|
|
1373
|
-
->on('workflow_status')
|
|
1374
|
-
->onDelete('cascade');
|
|
1375
|
-
});
|
|
1376
|
-
|
|
1377
|
-
Schema::create('event_dispatch_kv', function (Blueprint $table) {
|
|
1378
|
-
$table->string('service_name');
|
|
1379
|
-
$table->string('workflow_fn_name');
|
|
1380
|
-
$table->string('key');
|
|
1381
|
-
$table->text('value')->nullable();
|
|
1382
|
-
$table->bigInteger('update_time')->nullable();
|
|
1383
|
-
$table->bigInteger('update_seq')->nullable();
|
|
1384
|
-
|
|
1385
|
-
$table->primary(['service_name', 'workflow_fn_name', 'key']);
|
|
1386
|
-
$table->index('update_seq');
|
|
1387
|
-
});
|
|
1388
|
-
|
|
1389
|
-
Schema::create('workflow_streams', function (Blueprint $table) {
|
|
1390
|
-
$table->string('workflow_uuid');
|
|
1391
|
-
$table->string('key');
|
|
1392
|
-
$table->integer('offset');
|
|
1393
|
-
$table->text('value');
|
|
1394
|
-
$table->boolean('is_closed')->default(false);
|
|
1395
|
-
|
|
1396
|
-
$table->primary(['workflow_uuid', 'key', 'offset']);
|
|
1397
|
-
$table->foreign('workflow_uuid')
|
|
1398
|
-
->references('workflow_uuid')
|
|
1399
|
-
->on('workflow_status')
|
|
1400
|
-
->onDelete('cascade');
|
|
1401
|
-
});
|
|
1402
|
-
}
|
|
1403
|
-
|
|
1404
|
-
public function down(): void
|
|
1405
|
-
{
|
|
1406
|
-
Schema::dropIfExists('workflow_streams');
|
|
1407
|
-
Schema::dropIfExists('event_dispatch_kv');
|
|
1408
|
-
Schema::dropIfExists('workflow_events');
|
|
1409
|
-
Schema::dropIfExists('notifications');
|
|
1410
|
-
Schema::dropIfExists('operation_outputs');
|
|
1411
|
-
Schema::dropIfExists('workflow_status');
|
|
1412
|
-
}
|
|
1413
|
-
};
|
|
1414
|
-
```
|
|
1415
|
-
|
|
1416
|
-
### Key Implementation Notes for Laravel
|
|
1417
|
-
|
|
1418
|
-
1. **Atomic Operations**: Use database transactions for:
|
|
1419
|
-
|
|
1420
|
-
- `POST /workflows` - Check-and-insert must be atomic
|
|
1421
|
-
- `POST /queues/{name}/start-workflows` - Finding and updating must be atomic
|
|
1422
|
-
- `PUT /event-dispatch` - Optimistic locking on `update_seq`
|
|
1423
|
-
|
|
1424
|
-
2. **Soft Real-time**: For polling endpoints (`/result`, `/messages`, `/events`), consider:
|
|
1425
|
-
|
|
1426
|
-
- Long-polling with timeout
|
|
1427
|
-
- Or Laravel broadcasting with Pusher/WebSockets
|
|
1428
|
-
|
|
1429
|
-
3. **Cleanup**: The `POST /admin/garbage-collect` endpoint should delete:
|
|
1430
|
-
|
|
1431
|
-
- Completed workflows older than `cutoffEpochTimestampMs`
|
|
1432
|
-
- Associated operation_outputs, notifications, events, streams
|
|
1433
|
-
|
|
1434
|
-
4. **Serialization**: All `output`, `error`, `value`, `message`, `inputs` fields are opaque JSON strings. Store as TEXT and return unchanged.
|
|
1435
|
-
|
|
1436
|
-
---
|
|
1437
|
-
|
|
1438
|
-
## Version
|
|
1439
|
-
|
|
1440
|
-
API Schema Version: 1.0.0
|
|
1441
|
-
Generated for DBOS SDK HTTP Transport
|