@mastra/dynamodb 1.0.1 → 1.0.2-alpha.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/CHANGELOG.md +9 -0
- package/LICENSE.md +15 -0
- package/dist/docs/SKILL.md +1 -1
- package/dist/docs/assets/SOURCE_MAP.json +1 -1
- package/dist/docs/references/reference-storage-dynamodb.md +20 -20
- package/dist/index.cjs +164 -52
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +164 -52
- package/dist/index.js.map +1 -1
- package/dist/storage/domains/workflows/index.d.ts +9 -0
- package/dist/storage/domains/workflows/index.d.ts.map +1 -1
- package/package.json +8 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# @mastra/dynamodb
|
|
2
2
|
|
|
3
|
+
## 1.0.2-alpha.0
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Added atomic `updateWorkflowResults` and `updateWorkflowState` to safely merge concurrent step results into workflow snapshots. ([#12575](https://github.com/mastra-ai/mastra/pull/12575))
|
|
8
|
+
|
|
9
|
+
- Updated dependencies [[`504fc8b`](https://github.com/mastra-ai/mastra/commit/504fc8b9d0ddab717577ad3bf9c95ea4bd5377bd), [`f9c150b`](https://github.com/mastra-ai/mastra/commit/f9c150b7595ad05ad9cc9a11098e2944361e8c22), [`88de7e8`](https://github.com/mastra-ai/mastra/commit/88de7e8dfe4b7e1951a9e441bb33136e705ce24e), [`edee4b3`](https://github.com/mastra-ai/mastra/commit/edee4b37dff0af515fc7cc0e8d71ee39e6a762f0), [`3790c75`](https://github.com/mastra-ai/mastra/commit/3790c7578cc6a47d854eb12d89e6b1912867fe29), [`e7a235b`](https://github.com/mastra-ai/mastra/commit/e7a235be6472e0c870ed6c791ddb17c492dc188b), [`d51d298`](https://github.com/mastra-ai/mastra/commit/d51d298953967aab1f58ec965b644d109214f085), [`6dbeeb9`](https://github.com/mastra-ai/mastra/commit/6dbeeb94a8b1eebb727300d1a98961f882180794), [`d5f0d8d`](https://github.com/mastra-ai/mastra/commit/d5f0d8d6a03e515ddaa9b5da19b7e44b8357b07b), [`09c3b18`](https://github.com/mastra-ai/mastra/commit/09c3b1802ff14e243a8a8baea327440bc8cc2e32), [`b896379`](https://github.com/mastra-ai/mastra/commit/b8963791c6afa79484645fcec596a201f936b9a2), [`85c84eb`](https://github.com/mastra-ai/mastra/commit/85c84ebb78aebfcba9d209c8e152b16d7a00cb71), [`a89272a`](https://github.com/mastra-ai/mastra/commit/a89272a5d71939b9fcd284e6a6dc1dd091a6bdcf), [`ee9c8df`](https://github.com/mastra-ai/mastra/commit/ee9c8df644f19d055af5f496bf4942705f5a47b7), [`77b4a25`](https://github.com/mastra-ai/mastra/commit/77b4a254e51907f8ff3a3ba95596a18e93ae4b35), [`276246e`](https://github.com/mastra-ai/mastra/commit/276246e0b9066a1ea48bbc70df84dbe528daaf99), [`08ecfdb`](https://github.com/mastra-ai/mastra/commit/08ecfdbdad6fb8285deef86a034bdf4a6047cfca), [`d5f628c`](https://github.com/mastra-ai/mastra/commit/d5f628ca86c6f6f3ff1035d52f635df32dd81cab), [`524c0f3`](https://github.com/mastra-ai/mastra/commit/524c0f3c434c3d9d18f66338dcef383d6161b59c), [`c18a0e9`](https://github.com/mastra-ai/mastra/commit/c18a0e9cef1e4ca004b2963d35e4cfc031971eac), [`4bd21ea`](https://github.com/mastra-ai/mastra/commit/4bd21ea43d44d0a0427414fc047577f9f0aa3bec), [`115a7a4`](https://github.com/mastra-ai/mastra/commit/115a7a47db5e9896fec12ae6507501adb9ec89bf), [`22a48ae`](https://github.com/mastra-ai/mastra/commit/22a48ae2513eb54d8d79dad361fddbca97a155e8), [`3c6ef79`](https://github.com/mastra-ai/mastra/commit/3c6ef798481e00d6d22563be2de98818fd4dd5e0), [`9311c17`](https://github.com/mastra-ai/mastra/commit/9311c17d7a0640d9c4da2e71b814dc67c57c6369), [`7edf78f`](https://github.com/mastra-ai/mastra/commit/7edf78f80422c43e84585f08ba11df0d4d0b73c5), [`1c4221c`](https://github.com/mastra-ai/mastra/commit/1c4221cf6032ec98d0e094d4ee11da3e48490d96), [`d25b9ea`](https://github.com/mastra-ai/mastra/commit/d25b9eabd400167255a97b690ffbc4ee4097ded5), [`fe1ce5c`](https://github.com/mastra-ai/mastra/commit/fe1ce5c9211c03d561606fda95cbfe7df1d9a9b5), [`b03c0e0`](https://github.com/mastra-ai/mastra/commit/b03c0e0389a799523929a458b0509c9e4244d562), [`0a8366b`](https://github.com/mastra-ai/mastra/commit/0a8366b0a692fcdde56c4d526e4cf03c502ae4ac), [`85664e9`](https://github.com/mastra-ai/mastra/commit/85664e9fd857320fbc245e301f764f45f66f32a3), [`bc79650`](https://github.com/mastra-ai/mastra/commit/bc796500c6e0334faa158a96077e3fb332274869), [`9257d01`](https://github.com/mastra-ai/mastra/commit/9257d01d1366d81f84c582fe02b5e200cf9621f4), [`3a3a59e`](https://github.com/mastra-ai/mastra/commit/3a3a59e8ffaa6a985fe3d9a126a3f5ade11a6724), [`3108d4e`](https://github.com/mastra-ai/mastra/commit/3108d4e649c9fddbf03253a6feeb388a5fa9fa5a), [`0c33b2c`](https://github.com/mastra-ai/mastra/commit/0c33b2c9db537f815e1c59e2c898ffce2e395a79), [`191e5bd`](https://github.com/mastra-ai/mastra/commit/191e5bd29b82f5bda35243945790da7bc7b695c2), [`f77cd94`](https://github.com/mastra-ai/mastra/commit/f77cd94c44eabed490384e7d19232a865e13214c), [`e8135c7`](https://github.com/mastra-ai/mastra/commit/e8135c7e300dac5040670eec7eab896ac6092e30), [`daca48f`](https://github.com/mastra-ai/mastra/commit/daca48f0fb17b7ae0b62a2ac40cf0e491b2fd0b7), [`257d14f`](https://github.com/mastra-ai/mastra/commit/257d14faca5931f2e4186fc165b6f0b1f915deee), [`352f25d`](https://github.com/mastra-ai/mastra/commit/352f25da316b24cdd5b410fd8dddf6a8b763da2a), [`93477d0`](https://github.com/mastra-ai/mastra/commit/93477d0769b8a13ea5ed73d508d967fb23eaeed9), [`31c78b3`](https://github.com/mastra-ai/mastra/commit/31c78b3eb28f58a8017f1dcc795c33214d87feac), [`0bc0720`](https://github.com/mastra-ai/mastra/commit/0bc07201095791858087cc56f353fcd65e87ab54), [`36516ac`](https://github.com/mastra-ai/mastra/commit/36516aca1021cbeb42e74751b46a2614101f37c8), [`e947652`](https://github.com/mastra-ai/mastra/commit/e9476527fdecb4449e54570e80dfaf8466901254), [`3c6ef79`](https://github.com/mastra-ai/mastra/commit/3c6ef798481e00d6d22563be2de98818fd4dd5e0), [`9257d01`](https://github.com/mastra-ai/mastra/commit/9257d01d1366d81f84c582fe02b5e200cf9621f4), [`ec248f6`](https://github.com/mastra-ai/mastra/commit/ec248f6b56e8a037c066c49b2178e2507471d988)]:
|
|
10
|
+
- @mastra/core@1.9.0-alpha.0
|
|
11
|
+
|
|
3
12
|
## 1.0.1
|
|
4
13
|
|
|
5
14
|
### Patch Changes
|
package/LICENSE.md
CHANGED
|
@@ -1,3 +1,18 @@
|
|
|
1
|
+
Portions of this software are licensed as follows:
|
|
2
|
+
|
|
3
|
+
- All content that resides under any directory named "ee/" within this
|
|
4
|
+
repository, including but not limited to:
|
|
5
|
+
- `packages/core/src/auth/ee/`
|
|
6
|
+
- `packages/server/src/server/auth/ee/`
|
|
7
|
+
is licensed under the license defined in `ee/LICENSE`.
|
|
8
|
+
|
|
9
|
+
- All third-party components incorporated into the Mastra Software are
|
|
10
|
+
licensed under the original license provided by the owner of the
|
|
11
|
+
applicable component.
|
|
12
|
+
|
|
13
|
+
- Content outside of the above-mentioned directories or restrictions is
|
|
14
|
+
available under the "Apache License 2.0" as defined below.
|
|
15
|
+
|
|
1
16
|
# Apache License 2.0
|
|
2
17
|
|
|
3
18
|
Copyright (c) 2025 Kepler Software, Inc.
|
package/dist/docs/SKILL.md
CHANGED
|
@@ -53,19 +53,19 @@ Detailed instructions for setting up the table using AWS CloudFormation or AWS C
|
|
|
53
53
|
### Basic Usage
|
|
54
54
|
|
|
55
55
|
```typescript
|
|
56
|
-
import { Memory } from
|
|
57
|
-
import { DynamoDBStore } from
|
|
56
|
+
import { Memory } from '@mastra/memory'
|
|
57
|
+
import { DynamoDBStore } from '@mastra/dynamodb'
|
|
58
58
|
|
|
59
59
|
// Initialize the DynamoDB storage
|
|
60
60
|
const storage = new DynamoDBStore({
|
|
61
|
-
id:
|
|
61
|
+
id: 'dynamodb', // Unique identifier for this storage instance
|
|
62
62
|
config: {
|
|
63
|
-
tableName:
|
|
64
|
-
region:
|
|
63
|
+
tableName: 'mastra-single-table', // Name of your DynamoDB table
|
|
64
|
+
region: 'us-east-1', // Optional: AWS region, defaults to 'us-east-1'
|
|
65
65
|
// endpoint: "http://localhost:8000", // Optional: For local DynamoDB
|
|
66
66
|
// credentials: { accessKeyId: "YOUR_ACCESS_KEY", secretAccessKey: "YOUR_SECRET_KEY" } // Optional
|
|
67
67
|
},
|
|
68
|
-
})
|
|
68
|
+
})
|
|
69
69
|
|
|
70
70
|
// Example: Initialize Memory with DynamoDB storage
|
|
71
71
|
const memory = new Memory({
|
|
@@ -73,7 +73,7 @@ const memory = new Memory({
|
|
|
73
73
|
options: {
|
|
74
74
|
lastMessages: 10,
|
|
75
75
|
},
|
|
76
|
-
})
|
|
76
|
+
})
|
|
77
77
|
```
|
|
78
78
|
|
|
79
79
|
### Local Development with DynamoDB Local
|
|
@@ -89,19 +89,19 @@ For local development, you can use [DynamoDB Local](https://docs.aws.amazon.com/
|
|
|
89
89
|
2. **Configure `DynamoDBStore` to use the local endpoint:**
|
|
90
90
|
|
|
91
91
|
```typescript
|
|
92
|
-
import { DynamoDBStore } from
|
|
92
|
+
import { DynamoDBStore } from '@mastra/dynamodb'
|
|
93
93
|
|
|
94
94
|
const storage = new DynamoDBStore({
|
|
95
|
-
id:
|
|
95
|
+
id: 'dynamodb-local',
|
|
96
96
|
config: {
|
|
97
|
-
tableName:
|
|
98
|
-
region:
|
|
99
|
-
endpoint:
|
|
97
|
+
tableName: 'mastra-single-table', // Ensure this table is created in your local DynamoDB
|
|
98
|
+
region: 'localhost', // Can be any string for local, 'localhost' is common
|
|
99
|
+
endpoint: 'http://localhost:8000',
|
|
100
100
|
// For DynamoDB Local, credentials are not typically required unless configured.
|
|
101
101
|
// If you've configured local credentials:
|
|
102
102
|
// credentials: { accessKeyId: "fakeMyKeyId", secretAccessKey: "fakeSecretAccessKey" }
|
|
103
103
|
},
|
|
104
|
-
})
|
|
104
|
+
})
|
|
105
105
|
```
|
|
106
106
|
|
|
107
107
|
You will still need to create the table and GSIs in your local DynamoDB instance, for example, using the AWS CLI pointed to your local endpoint.
|
|
@@ -137,13 +137,13 @@ To use TTL, you must:
|
|
|
137
137
|
2. **Enable TTL on your DynamoDB table** via AWS Console or CLI, specifying the attribute name (default: `ttl`)
|
|
138
138
|
|
|
139
139
|
```typescript
|
|
140
|
-
import { DynamoDBStore } from
|
|
140
|
+
import { DynamoDBStore } from '@mastra/dynamodb'
|
|
141
141
|
|
|
142
142
|
const storage = new DynamoDBStore({
|
|
143
|
-
name:
|
|
143
|
+
name: 'dynamodb',
|
|
144
144
|
config: {
|
|
145
|
-
tableName:
|
|
146
|
-
region:
|
|
145
|
+
tableName: 'mastra-single-table',
|
|
146
|
+
region: 'us-east-1',
|
|
147
147
|
ttl: {
|
|
148
148
|
// Messages expire after 30 days
|
|
149
149
|
message: {
|
|
@@ -158,7 +158,7 @@ const storage = new DynamoDBStore({
|
|
|
158
158
|
// Traces expire after 7 days with custom attribute name
|
|
159
159
|
trace: {
|
|
160
160
|
enabled: true,
|
|
161
|
-
attributeName:
|
|
161
|
+
attributeName: 'expiresAt', // Custom TTL attribute
|
|
162
162
|
defaultTtlSeconds: 7 * 24 * 60 * 60, // 7 days
|
|
163
163
|
},
|
|
164
164
|
// Workflow snapshots don't expire
|
|
@@ -167,7 +167,7 @@ const storage = new DynamoDBStore({
|
|
|
167
167
|
},
|
|
168
168
|
},
|
|
169
169
|
},
|
|
170
|
-
})
|
|
170
|
+
})
|
|
171
171
|
```
|
|
172
172
|
|
|
173
173
|
### Supported Entity Types
|
|
@@ -214,7 +214,7 @@ aws dynamodb update-time-to-live \
|
|
|
214
214
|
4. Under "Time to Live (TTL)", click "Manage TTL"
|
|
215
215
|
5. Enable TTL and specify the attribute name (default: `ttl`)
|
|
216
216
|
|
|
217
|
-
> **Note
|
|
217
|
+
> **Note:** DynamoDB deletes expired items within 48 hours after expiration. Items remain queryable until actually deleted.
|
|
218
218
|
|
|
219
219
|
## AWS IAM Permissions
|
|
220
220
|
|
package/dist/index.cjs
CHANGED
|
@@ -2144,6 +2144,8 @@ function formatWorkflowRun(snapshotData) {
|
|
|
2144
2144
|
resourceId: snapshotData.resourceId
|
|
2145
2145
|
};
|
|
2146
2146
|
}
|
|
2147
|
+
var MAX_RETRIES = 5;
|
|
2148
|
+
var BASE_DELAY_MS = 50;
|
|
2147
2149
|
var WorkflowStorageDynamoDB = class extends storage.WorkflowsStorage {
|
|
2148
2150
|
service;
|
|
2149
2151
|
ttlConfig;
|
|
@@ -2153,9 +2155,41 @@ var WorkflowStorageDynamoDB = class extends storage.WorkflowsStorage {
|
|
|
2153
2155
|
this.service = resolved.service;
|
|
2154
2156
|
this.ttlConfig = resolved.ttl;
|
|
2155
2157
|
}
|
|
2158
|
+
supportsConcurrentUpdates() {
|
|
2159
|
+
return true;
|
|
2160
|
+
}
|
|
2156
2161
|
async dangerouslyClearAll() {
|
|
2157
2162
|
await deleteTableData(this.service, storage.TABLE_WORKFLOW_SNAPSHOT);
|
|
2158
2163
|
}
|
|
2164
|
+
/**
|
|
2165
|
+
* Helper to check if an error is a DynamoDB conditional check failure
|
|
2166
|
+
*/
|
|
2167
|
+
isConditionalCheckFailed(error) {
|
|
2168
|
+
if (error && typeof error === "object") {
|
|
2169
|
+
const err = error;
|
|
2170
|
+
if (err.name === "ConditionalCheckFailedException" || err.code === "ConditionalCheckFailedException" || (err.__type?.includes("ConditionalCheckFailedException") ?? false)) {
|
|
2171
|
+
return true;
|
|
2172
|
+
}
|
|
2173
|
+
if (err.message?.includes("conditional request failed")) {
|
|
2174
|
+
return true;
|
|
2175
|
+
}
|
|
2176
|
+
if (err.cause && typeof err.cause === "object") {
|
|
2177
|
+
const cause = err.cause;
|
|
2178
|
+
if (cause.name === "ConditionalCheckFailedException" || cause.code === "ConditionalCheckFailedException") {
|
|
2179
|
+
return true;
|
|
2180
|
+
}
|
|
2181
|
+
}
|
|
2182
|
+
}
|
|
2183
|
+
return false;
|
|
2184
|
+
}
|
|
2185
|
+
/**
|
|
2186
|
+
* Helper to delay with exponential backoff and jitter
|
|
2187
|
+
*/
|
|
2188
|
+
async delay(attempt) {
|
|
2189
|
+
const backoff = BASE_DELAY_MS * Math.pow(2, attempt);
|
|
2190
|
+
const jitter = Math.random() * backoff * 0.5;
|
|
2191
|
+
await new Promise((resolve) => setTimeout(resolve, backoff + jitter));
|
|
2192
|
+
}
|
|
2159
2193
|
async updateWorkflowResults({
|
|
2160
2194
|
workflowName,
|
|
2161
2195
|
runId,
|
|
@@ -2163,69 +2197,147 @@ var WorkflowStorageDynamoDB = class extends storage.WorkflowsStorage {
|
|
|
2163
2197
|
result,
|
|
2164
2198
|
requestContext
|
|
2165
2199
|
}) {
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2200
|
+
for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {
|
|
2201
|
+
try {
|
|
2202
|
+
const existingRecord = await this.service.entities.workflow_snapshot.get({
|
|
2203
|
+
entity: "workflow_snapshot",
|
|
2204
|
+
workflow_name: workflowName,
|
|
2205
|
+
run_id: runId
|
|
2206
|
+
}).go();
|
|
2207
|
+
const now = /* @__PURE__ */ new Date();
|
|
2208
|
+
let snapshot;
|
|
2209
|
+
let previousUpdatedAt;
|
|
2210
|
+
if (!existingRecord.data) {
|
|
2211
|
+
snapshot = {
|
|
2212
|
+
context: {},
|
|
2213
|
+
activePaths: [],
|
|
2214
|
+
timestamp: Date.now(),
|
|
2215
|
+
suspendedPaths: {},
|
|
2216
|
+
activeStepsPath: {},
|
|
2217
|
+
resumeLabels: {},
|
|
2218
|
+
serializedStepGraph: [],
|
|
2219
|
+
status: "pending",
|
|
2220
|
+
value: {},
|
|
2221
|
+
waitingPaths: {},
|
|
2222
|
+
runId,
|
|
2223
|
+
requestContext: {}
|
|
2224
|
+
};
|
|
2225
|
+
} else {
|
|
2226
|
+
snapshot = existingRecord.data.snapshot;
|
|
2227
|
+
previousUpdatedAt = existingRecord.data.updatedAt;
|
|
2228
|
+
}
|
|
2229
|
+
snapshot.context[stepId] = result;
|
|
2230
|
+
snapshot.requestContext = { ...snapshot.requestContext, ...requestContext };
|
|
2231
|
+
const data = {
|
|
2232
|
+
entity: "workflow_snapshot",
|
|
2233
|
+
workflow_name: workflowName,
|
|
2234
|
+
run_id: runId,
|
|
2235
|
+
snapshot: JSON.stringify(snapshot),
|
|
2236
|
+
createdAt: existingRecord.data?.createdAt ?? now.toISOString(),
|
|
2237
|
+
updatedAt: now.toISOString(),
|
|
2238
|
+
...getTtlProps("workflow_snapshot", this.ttlConfig)
|
|
2183
2239
|
};
|
|
2184
|
-
|
|
2185
|
-
|
|
2240
|
+
if (previousUpdatedAt) {
|
|
2241
|
+
await this.service.entities.workflow_snapshot.upsert(data).where((attr, op) => op.eq(attr.updatedAt, previousUpdatedAt)).go();
|
|
2242
|
+
} else {
|
|
2243
|
+
await this.service.entities.workflow_snapshot.create(data).where((attr, op) => op.notExists(attr.run_id)).go();
|
|
2244
|
+
}
|
|
2245
|
+
return snapshot.context;
|
|
2246
|
+
} catch (error$1) {
|
|
2247
|
+
if (this.isConditionalCheckFailed(error$1)) {
|
|
2248
|
+
if (attempt < MAX_RETRIES - 1) {
|
|
2249
|
+
this.logger.debug(
|
|
2250
|
+
`Optimistic locking conflict in updateWorkflowResults, retrying (attempt ${attempt + 1})`
|
|
2251
|
+
);
|
|
2252
|
+
await this.delay(attempt);
|
|
2253
|
+
continue;
|
|
2254
|
+
}
|
|
2255
|
+
}
|
|
2256
|
+
if (error$1 instanceof error.MastraError) throw error$1;
|
|
2257
|
+
throw new error.MastraError(
|
|
2258
|
+
{
|
|
2259
|
+
id: storage.createStorageErrorId("DYNAMODB", "UPDATE_WORKFLOW_RESULTS", "FAILED"),
|
|
2260
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2261
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
2262
|
+
details: { workflowName, runId, stepId }
|
|
2263
|
+
},
|
|
2264
|
+
error$1
|
|
2265
|
+
);
|
|
2186
2266
|
}
|
|
2187
|
-
snapshot.context[stepId] = result;
|
|
2188
|
-
snapshot.requestContext = { ...snapshot.requestContext, ...requestContext };
|
|
2189
|
-
await this.persistWorkflowSnapshot({ workflowName, runId, snapshot });
|
|
2190
|
-
return snapshot.context;
|
|
2191
|
-
} catch (error$1) {
|
|
2192
|
-
if (error$1 instanceof error.MastraError) throw error$1;
|
|
2193
|
-
throw new error.MastraError(
|
|
2194
|
-
{
|
|
2195
|
-
id: storage.createStorageErrorId("DYNAMODB", "UPDATE_WORKFLOW_RESULTS", "FAILED"),
|
|
2196
|
-
domain: error.ErrorDomain.STORAGE,
|
|
2197
|
-
category: error.ErrorCategory.THIRD_PARTY,
|
|
2198
|
-
details: { workflowName, runId, stepId }
|
|
2199
|
-
},
|
|
2200
|
-
error$1
|
|
2201
|
-
);
|
|
2202
2267
|
}
|
|
2268
|
+
throw new error.MastraError(
|
|
2269
|
+
{
|
|
2270
|
+
id: storage.createStorageErrorId("DYNAMODB", "UPDATE_WORKFLOW_RESULTS", "MAX_RETRIES_EXCEEDED"),
|
|
2271
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2272
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
2273
|
+
details: { workflowName, runId, stepId }
|
|
2274
|
+
},
|
|
2275
|
+
new Error("Max retries exceeded for optimistic locking")
|
|
2276
|
+
);
|
|
2203
2277
|
}
|
|
2204
2278
|
async updateWorkflowState({
|
|
2205
2279
|
workflowName,
|
|
2206
2280
|
runId,
|
|
2207
2281
|
opts
|
|
2208
2282
|
}) {
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2283
|
+
for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {
|
|
2284
|
+
try {
|
|
2285
|
+
const existingRecord = await this.service.entities.workflow_snapshot.get({
|
|
2286
|
+
entity: "workflow_snapshot",
|
|
2287
|
+
workflow_name: workflowName,
|
|
2288
|
+
run_id: runId
|
|
2289
|
+
}).go();
|
|
2290
|
+
if (!existingRecord.data) {
|
|
2291
|
+
return void 0;
|
|
2292
|
+
}
|
|
2293
|
+
const existingSnapshot = existingRecord.data.snapshot;
|
|
2294
|
+
if (!existingSnapshot || !existingSnapshot.context) {
|
|
2295
|
+
return void 0;
|
|
2296
|
+
}
|
|
2297
|
+
const previousUpdatedAt = existingRecord.data.updatedAt;
|
|
2298
|
+
const updatedSnapshot = { ...existingSnapshot, ...opts };
|
|
2299
|
+
const now = /* @__PURE__ */ new Date();
|
|
2300
|
+
const data = {
|
|
2301
|
+
entity: "workflow_snapshot",
|
|
2302
|
+
workflow_name: workflowName,
|
|
2303
|
+
run_id: runId,
|
|
2304
|
+
snapshot: JSON.stringify(updatedSnapshot),
|
|
2305
|
+
createdAt: existingRecord.data.createdAt,
|
|
2306
|
+
updatedAt: now.toISOString(),
|
|
2307
|
+
resourceId: existingRecord.data.resourceId,
|
|
2308
|
+
...getTtlProps("workflow_snapshot", this.ttlConfig)
|
|
2309
|
+
};
|
|
2310
|
+
await this.service.entities.workflow_snapshot.upsert(data).where((attr, op) => op.eq(attr.updatedAt, previousUpdatedAt)).go();
|
|
2311
|
+
return updatedSnapshot;
|
|
2312
|
+
} catch (error$1) {
|
|
2313
|
+
if (this.isConditionalCheckFailed(error$1)) {
|
|
2314
|
+
if (attempt < MAX_RETRIES - 1) {
|
|
2315
|
+
this.logger.debug(`Optimistic locking conflict in updateWorkflowState, retrying (attempt ${attempt + 1})`);
|
|
2316
|
+
await this.delay(attempt);
|
|
2317
|
+
continue;
|
|
2318
|
+
}
|
|
2319
|
+
}
|
|
2320
|
+
if (error$1 instanceof error.MastraError) throw error$1;
|
|
2321
|
+
throw new error.MastraError(
|
|
2322
|
+
{
|
|
2323
|
+
id: storage.createStorageErrorId("DYNAMODB", "UPDATE_WORKFLOW_STATE", "FAILED"),
|
|
2324
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2325
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
2326
|
+
details: { workflowName, runId }
|
|
2327
|
+
},
|
|
2328
|
+
error$1
|
|
2329
|
+
);
|
|
2213
2330
|
}
|
|
2214
|
-
const updatedSnapshot = { ...existingSnapshot, ...opts };
|
|
2215
|
-
await this.persistWorkflowSnapshot({ workflowName, runId, snapshot: updatedSnapshot });
|
|
2216
|
-
return updatedSnapshot;
|
|
2217
|
-
} catch (error$1) {
|
|
2218
|
-
if (error$1 instanceof error.MastraError) throw error$1;
|
|
2219
|
-
throw new error.MastraError(
|
|
2220
|
-
{
|
|
2221
|
-
id: storage.createStorageErrorId("DYNAMODB", "UPDATE_WORKFLOW_STATE", "FAILED"),
|
|
2222
|
-
domain: error.ErrorDomain.STORAGE,
|
|
2223
|
-
category: error.ErrorCategory.THIRD_PARTY,
|
|
2224
|
-
details: { workflowName, runId }
|
|
2225
|
-
},
|
|
2226
|
-
error$1
|
|
2227
|
-
);
|
|
2228
2331
|
}
|
|
2332
|
+
throw new error.MastraError(
|
|
2333
|
+
{
|
|
2334
|
+
id: storage.createStorageErrorId("DYNAMODB", "UPDATE_WORKFLOW_STATE", "MAX_RETRIES_EXCEEDED"),
|
|
2335
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2336
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
2337
|
+
details: { workflowName, runId }
|
|
2338
|
+
},
|
|
2339
|
+
new Error("Max retries exceeded for optimistic locking")
|
|
2340
|
+
);
|
|
2229
2341
|
}
|
|
2230
2342
|
// Workflow operations
|
|
2231
2343
|
async persistWorkflowSnapshot({
|