@mastra/mongodb 1.23.1-alpha.0 → 1.23.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/docs/SKILL.md +1 -1
- package/dist/docs/assets/SOURCE_MAP.json +1 -1
- package/dist/docs/references/reference-storage-composite.md +34 -0
- package/dist/docs/references/reference-vectors-mongodb.md +2 -1
- package/dist/index.cjs +432 -118
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +433 -119
- package/dist/index.js.map +1 -1
- package/dist/storage/connectors/MongoDBConnector.d.ts +10 -3
- package/dist/storage/connectors/MongoDBConnector.d.ts.map +1 -1
- package/dist/storage/domains/memory/index.d.ts +28 -11
- package/dist/storage/domains/memory/index.d.ts.map +1 -1
- package/dist/storage/domains/run-fencing.d.ts +39 -0
- package/dist/storage/domains/run-fencing.d.ts.map +1 -0
- package/dist/storage/domains/workflows/index.d.ts +26 -9
- package/dist/storage/domains/workflows/index.d.ts.map +1 -1
- package/dist/storage/retention.d.ts +9 -5
- package/dist/storage/retention.d.ts.map +1 -1
- package/package.json +8 -8
package/dist/index.cjs
CHANGED
|
@@ -10,7 +10,7 @@ let _mastra_core_agent = require("@mastra/core/agent");
|
|
|
10
10
|
let _mastra_core_evals = require("@mastra/core/evals");
|
|
11
11
|
let _mastra_core_storage_domains_skills = require("@mastra/core/storage/domains/skills");
|
|
12
12
|
//#region package.json
|
|
13
|
-
var version = "1.23.1
|
|
13
|
+
var version = "1.23.1";
|
|
14
14
|
//#endregion
|
|
15
15
|
//#region src/vector/filter.ts
|
|
16
16
|
/**
|
|
@@ -1619,20 +1619,29 @@ var MongoDBConnector = class MongoDBConnector {
|
|
|
1619
1619
|
return (await this.getConnection()).listCollections({ name: collectionName }).hasNext();
|
|
1620
1620
|
}
|
|
1621
1621
|
/**
|
|
1622
|
-
*
|
|
1623
|
-
*
|
|
1624
|
-
*
|
|
1622
|
+
* Whether the deployment supports multi-document transactions (replica set
|
|
1623
|
+
* or sharded cluster). Standalone servers and custom connector handlers
|
|
1624
|
+
* don't. The answer is cached once a probe completes; a probe that fails
|
|
1625
|
+
* rejects and is retried on the next call, so the answer never changes.
|
|
1625
1626
|
*/
|
|
1626
|
-
async
|
|
1627
|
+
async probeTransactions() {
|
|
1627
1628
|
if (this.#supportsTransactions !== void 0) return this.#supportsTransactions;
|
|
1628
1629
|
if (!this.#client) {
|
|
1629
1630
|
this.#supportsTransactions = false;
|
|
1630
1631
|
return false;
|
|
1631
1632
|
}
|
|
1633
|
+
const hello = await (await this.getConnection()).admin().command({ hello: 1 });
|
|
1634
|
+
this.#supportsTransactions = Boolean(hello.setName) || hello.msg === "isdbgrid";
|
|
1635
|
+
return this.#supportsTransactions;
|
|
1636
|
+
}
|
|
1637
|
+
/**
|
|
1638
|
+
* Like {@link probeTransactions}, but a failed probe reads as no
|
|
1639
|
+
* transaction support (and is retried on the next call), so a momentary
|
|
1640
|
+
* outage degrades writes to non-atomic instead of failing them.
|
|
1641
|
+
*/
|
|
1642
|
+
async supportsTransactions() {
|
|
1632
1643
|
try {
|
|
1633
|
-
|
|
1634
|
-
this.#supportsTransactions = Boolean(hello.setName) || hello.msg === "isdbgrid";
|
|
1635
|
-
return this.#supportsTransactions;
|
|
1644
|
+
return await this.probeTransactions();
|
|
1636
1645
|
} catch {
|
|
1637
1646
|
return false;
|
|
1638
1647
|
}
|
|
@@ -2279,14 +2288,19 @@ function cutoffFor(policy, encoding, now = Date.now()) {
|
|
|
2279
2288
|
* Delete up to `limit` documents whose anchor field is older than `cutoff`.
|
|
2280
2289
|
*
|
|
2281
2290
|
* `deleteMany` has no limit clause, so each batch first collects `_id`s with a
|
|
2282
|
-
* bounded `find`, then deletes
|
|
2283
|
-
*
|
|
2291
|
+
* bounded `find`, then deletes that set — the Mongo equivalent of the SQL
|
|
2292
|
+
* stores' `DELETE ... WHERE rowid/ctid IN (SELECT ... LIMIT n)` pattern. The
|
|
2293
|
+
* delete re-checks the anchor, so a document updated after the `find` (a
|
|
2294
|
+
* renewed run ownership, a touched snapshot) survives.
|
|
2284
2295
|
*/
|
|
2285
2296
|
async function pruneCollectionBatch({ connector, table, column, cutoff, limit }) {
|
|
2286
2297
|
const collection = await connector.getCollection(table);
|
|
2287
2298
|
const docs = await collection.find({ [column]: { $lt: cutoff } }).project({ _id: 1 }).limit(limit).toArray();
|
|
2288
2299
|
if (docs.length === 0) return 0;
|
|
2289
|
-
return (await collection.deleteMany({
|
|
2300
|
+
return (await collection.deleteMany({
|
|
2301
|
+
_id: { $in: docs.map((doc) => doc._id) },
|
|
2302
|
+
[column]: { $lt: cutoff }
|
|
2303
|
+
})).deletedCount;
|
|
2290
2304
|
}
|
|
2291
2305
|
/**
|
|
2292
2306
|
* Run the bounded/cancellable batched-delete loop for a single logical target,
|
|
@@ -6561,6 +6575,40 @@ function isAppendOnlySince(storedObservations, snapshotObservations) {
|
|
|
6561
6575
|
return stored === snapshot || stored.startsWith(snapshot);
|
|
6562
6576
|
}
|
|
6563
6577
|
//#endregion
|
|
6578
|
+
//#region src/storage/domains/run-fencing.ts
|
|
6579
|
+
async function getRunClaims(connector, name) {
|
|
6580
|
+
return await connector.getCollection(name);
|
|
6581
|
+
}
|
|
6582
|
+
/** Duplicate-key error: an upsert lost the race to insert the document. */
|
|
6583
|
+
function isDuplicateKeyError(error) {
|
|
6584
|
+
return error?.code === 11e3;
|
|
6585
|
+
}
|
|
6586
|
+
/**
|
|
6587
|
+
* Runs a write, fenced when `check` is set. A fenced write runs in a
|
|
6588
|
+
* transaction that first updates the run's claim document, matching it on
|
|
6589
|
+
* the fence. A fence that is no longer current matches nothing, and the write
|
|
6590
|
+
* throws `RunFenceConflictError` before anything is written. A claim that
|
|
6591
|
+
* changes while the transaction runs makes the update conflict, so the
|
|
6592
|
+
* transaction retries and sees the new claim; a claim attempted after the
|
|
6593
|
+
* update waits until the transaction commits. Updating the claim document,
|
|
6594
|
+
* rather than reading it, is what makes concurrent claims conflict.
|
|
6595
|
+
*
|
|
6596
|
+
* Fencing is declared only on deployments that support transactions.
|
|
6597
|
+
*/
|
|
6598
|
+
async function withRunFence(connector, check, write) {
|
|
6599
|
+
if (!check) return write();
|
|
6600
|
+
const { claims, fence, operation } = check;
|
|
6601
|
+
const collection = await getRunClaims(connector, claims);
|
|
6602
|
+
return connector.withTransaction(async (session) => {
|
|
6603
|
+
if ((await collection.updateOne({
|
|
6604
|
+
_id: fence.runId,
|
|
6605
|
+
generation: fence.generation,
|
|
6606
|
+
ownerId: fence.ownerId
|
|
6607
|
+
}, { $inc: { fencedWrites: 1 } }, { session })).matchedCount === 0) throw new _mastra_core_storage.RunFenceConflictError(fence, operation);
|
|
6608
|
+
return write(session);
|
|
6609
|
+
});
|
|
6610
|
+
}
|
|
6611
|
+
//#endregion
|
|
6564
6612
|
//#region src/storage/domains/memory/index.ts
|
|
6565
6613
|
/**
|
|
6566
6614
|
* Local constant for the observational memory table name.
|
|
@@ -6630,9 +6678,6 @@ function buildSuccessorDocument(old, pending) {
|
|
|
6630
6678
|
function matchStoredFields(doc, fields) {
|
|
6631
6679
|
return Object.fromEntries(fields.map((f) => [f, doc[f] === void 0 ? { $exists: false } : doc[f]]));
|
|
6632
6680
|
}
|
|
6633
|
-
function isDuplicateKeyError(error) {
|
|
6634
|
-
return error?.code === 11e3;
|
|
6635
|
-
}
|
|
6636
6681
|
function omNotFound(operation, id) {
|
|
6637
6682
|
return new _mastra_core_error.MastraError({
|
|
6638
6683
|
id: (0, _mastra_core_storage.createStorageErrorId)("MONGODB", operation, "NOT_FOUND"),
|
|
@@ -6672,11 +6717,14 @@ var MemoryStorageMongoDB = class MemoryStorageMongoDB extends _mastra_core_stora
|
|
|
6672
6717
|
_mastra_core_storage.TABLE_THREADS,
|
|
6673
6718
|
_mastra_core_storage.TABLE_MESSAGES,
|
|
6674
6719
|
_mastra_core_storage.TABLE_RESOURCES,
|
|
6675
|
-
OM_TABLE
|
|
6720
|
+
OM_TABLE,
|
|
6721
|
+
_mastra_core_storage.TABLE_MEMORY_RUN_FENCES
|
|
6676
6722
|
];
|
|
6677
6723
|
/**
|
|
6678
6724
|
* Retention-eligible collections. The observational-memory collection is
|
|
6679
6725
|
* excluded: it has no timestamp anchor to age on. All anchors are BSON dates.
|
|
6726
|
+
* A run fence's `retiredAt` stays null until the execution holding it
|
|
6727
|
+
* settles, and null is never pruned.
|
|
6680
6728
|
*/
|
|
6681
6729
|
static retentionTables = {
|
|
6682
6730
|
messages: {
|
|
@@ -6693,6 +6741,11 @@ var MemoryStorageMongoDB = class MemoryStorageMongoDB extends _mastra_core_stora
|
|
|
6693
6741
|
table: _mastra_core_storage.TABLE_THREADS,
|
|
6694
6742
|
column: "createdAt",
|
|
6695
6743
|
indexed: true
|
|
6744
|
+
},
|
|
6745
|
+
runFences: {
|
|
6746
|
+
table: _mastra_core_storage.TABLE_MEMORY_RUN_FENCES,
|
|
6747
|
+
column: "retiredAt",
|
|
6748
|
+
indexed: true
|
|
6696
6749
|
}
|
|
6697
6750
|
};
|
|
6698
6751
|
constructor(config) {
|
|
@@ -6711,11 +6764,76 @@ var MemoryStorageMongoDB = class MemoryStorageMongoDB extends _mastra_core_stora
|
|
|
6711
6764
|
await this.#maintainSupersededBy();
|
|
6712
6765
|
}
|
|
6713
6766
|
/**
|
|
6767
|
+
* Fenced writes need multi-document transactions, so only replica sets and
|
|
6768
|
+
* sharded clusters fence. Rejects while the deployment can't be probed.
|
|
6769
|
+
*/
|
|
6770
|
+
supportsRunFencing() {
|
|
6771
|
+
return this.#connector.probeTransactions();
|
|
6772
|
+
}
|
|
6773
|
+
async raiseRunFence(fence) {
|
|
6774
|
+
try {
|
|
6775
|
+
const fences = await getRunClaims(this.#connector, _mastra_core_storage.TABLE_MEMORY_RUN_FENCES);
|
|
6776
|
+
for (;;) {
|
|
6777
|
+
try {
|
|
6778
|
+
await fences.updateOne({
|
|
6779
|
+
_id: fence.runId,
|
|
6780
|
+
$or: [{ generation: { $lt: fence.generation } }, {
|
|
6781
|
+
generation: fence.generation,
|
|
6782
|
+
ownerId: fence.ownerId
|
|
6783
|
+
}]
|
|
6784
|
+
}, { $set: {
|
|
6785
|
+
generation: fence.generation,
|
|
6786
|
+
ownerId: fence.ownerId,
|
|
6787
|
+
retiredAt: null
|
|
6788
|
+
} }, { upsert: true });
|
|
6789
|
+
return true;
|
|
6790
|
+
} catch (error) {
|
|
6791
|
+
if (!isDuplicateKeyError(error)) throw error;
|
|
6792
|
+
}
|
|
6793
|
+
const current = await fences.findOne({ _id: fence.runId });
|
|
6794
|
+
if (current && current.generation >= fence.generation) return current.generation === fence.generation && current.ownerId === fence.ownerId;
|
|
6795
|
+
}
|
|
6796
|
+
} catch (error) {
|
|
6797
|
+
throw new _mastra_core_error.MastraError({
|
|
6798
|
+
id: (0, _mastra_core_storage.createStorageErrorId)("MONGODB", "RAISE_RUN_FENCE", "FAILED"),
|
|
6799
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
6800
|
+
category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
|
|
6801
|
+
details: { runId: fence.runId }
|
|
6802
|
+
}, error);
|
|
6803
|
+
}
|
|
6804
|
+
}
|
|
6805
|
+
async retireRunFence(fence) {
|
|
6806
|
+
try {
|
|
6807
|
+
return (await (await getRunClaims(this.#connector, _mastra_core_storage.TABLE_MEMORY_RUN_FENCES)).updateOne({
|
|
6808
|
+
_id: fence.runId,
|
|
6809
|
+
generation: fence.generation,
|
|
6810
|
+
ownerId: fence.ownerId
|
|
6811
|
+
}, [{ $set: { retiredAt: "$$NOW" } }])).matchedCount > 0;
|
|
6812
|
+
} catch (error) {
|
|
6813
|
+
throw new _mastra_core_error.MastraError({
|
|
6814
|
+
id: (0, _mastra_core_storage.createStorageErrorId)("MONGODB", "RETIRE_RUN_FENCE", "FAILED"),
|
|
6815
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
6816
|
+
category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
|
|
6817
|
+
details: { runId: fence.runId }
|
|
6818
|
+
}, error);
|
|
6819
|
+
}
|
|
6820
|
+
}
|
|
6821
|
+
/** The check a write must pass: its own fence, otherwise the one in scope. */
|
|
6822
|
+
#runFenceCheck(fence, operation) {
|
|
6823
|
+
const resolved = (0, _mastra_core_storage.resolveRunFence)(this, fence);
|
|
6824
|
+
return resolved && {
|
|
6825
|
+
claims: _mastra_core_storage.TABLE_MEMORY_RUN_FENCES,
|
|
6826
|
+
fence: resolved,
|
|
6827
|
+
operation
|
|
6828
|
+
};
|
|
6829
|
+
}
|
|
6830
|
+
/**
|
|
6714
6831
|
* Delete memory rows older than each table's `maxAge`, batched. Order is
|
|
6715
6832
|
* messages → resources → threads so child rows never outlive the delete of
|
|
6716
|
-
* their thread
|
|
6717
|
-
*
|
|
6718
|
-
*
|
|
6833
|
+
* their thread; run fences are independent and go last. Like
|
|
6834
|
+
* `deleteThread()`, this does not sweep vector-store embeddings —
|
|
6835
|
+
* semantic-recall vectors live in a separate vector store the memory domain
|
|
6836
|
+
* cannot reach; cleaning those up is the operator's concern.
|
|
6719
6837
|
*/
|
|
6720
6838
|
async prune(policies, options) {
|
|
6721
6839
|
const targets = resolveTargets({
|
|
@@ -6724,7 +6842,8 @@ var MemoryStorageMongoDB = class MemoryStorageMongoDB extends _mastra_core_stora
|
|
|
6724
6842
|
order: [
|
|
6725
6843
|
"messages",
|
|
6726
6844
|
"resources",
|
|
6727
|
-
"threads"
|
|
6845
|
+
"threads",
|
|
6846
|
+
"runFences"
|
|
6728
6847
|
]
|
|
6729
6848
|
});
|
|
6730
6849
|
return runPrune({
|
|
@@ -6830,17 +6949,19 @@ var MemoryStorageMongoDB = class MemoryStorageMongoDB extends _mastra_core_stora
|
|
|
6830
6949
|
}
|
|
6831
6950
|
}
|
|
6832
6951
|
async dangerouslyClearAll() {
|
|
6833
|
-
const [threadsCollection, messagesCollection, resourcesCollection, omCollection] = await Promise.all([
|
|
6952
|
+
const [threadsCollection, messagesCollection, resourcesCollection, omCollection, fencesCollection] = await Promise.all([
|
|
6834
6953
|
this.getCollection(_mastra_core_storage.TABLE_THREADS),
|
|
6835
6954
|
this.getCollection(_mastra_core_storage.TABLE_MESSAGES),
|
|
6836
6955
|
this.getCollection(_mastra_core_storage.TABLE_RESOURCES),
|
|
6837
|
-
this.getCollection(OM_TABLE)
|
|
6956
|
+
this.getCollection(OM_TABLE),
|
|
6957
|
+
this.getCollection(_mastra_core_storage.TABLE_MEMORY_RUN_FENCES)
|
|
6838
6958
|
]);
|
|
6839
6959
|
await Promise.all([
|
|
6840
6960
|
threadsCollection.deleteMany({}),
|
|
6841
6961
|
messagesCollection.deleteMany({}),
|
|
6842
6962
|
resourcesCollection.deleteMany({}),
|
|
6843
|
-
omCollection.deleteMany({})
|
|
6963
|
+
omCollection.deleteMany({}),
|
|
6964
|
+
fencesCollection.deleteMany({})
|
|
6844
6965
|
]);
|
|
6845
6966
|
}
|
|
6846
6967
|
parseRow(row) {
|
|
@@ -7196,7 +7317,7 @@ var MemoryStorageMongoDB = class MemoryStorageMongoDB extends _mastra_core_stora
|
|
|
7196
7317
|
throw mastraError;
|
|
7197
7318
|
}
|
|
7198
7319
|
}
|
|
7199
|
-
async saveMessages({ messages }) {
|
|
7320
|
+
async saveMessages({ messages, fence }) {
|
|
7200
7321
|
if (messages.length === 0) return { messages: [] };
|
|
7201
7322
|
try {
|
|
7202
7323
|
if (!messages[0]?.threadId) throw new Error("Thread ID is required");
|
|
@@ -7224,12 +7345,16 @@ var MemoryStorageMongoDB = class MemoryStorageMongoDB extends _mastra_core_stora
|
|
|
7224
7345
|
});
|
|
7225
7346
|
const allThreadIds = new Set(messages.map((m) => m.threadId));
|
|
7226
7347
|
const now = /* @__PURE__ */ new Date();
|
|
7227
|
-
|
|
7348
|
+
const writeMessages = async (session) => {
|
|
7228
7349
|
await collection.bulkWrite(messagesToInsert, { session });
|
|
7229
7350
|
for (const tid of allThreadIds) await threadsCollection.updateOne({ id: tid }, { $set: { updatedAt: now } }, { session });
|
|
7230
|
-
}
|
|
7351
|
+
};
|
|
7352
|
+
const check = this.#runFenceCheck(fence, "saveMessages");
|
|
7353
|
+
if (check) await withRunFence(this.#connector, check, writeMessages);
|
|
7354
|
+
else await this.#connector.withTransaction(writeMessages);
|
|
7231
7355
|
return { messages: new _mastra_core_agent.MessageList().add(messages, "memory").get.all.db() };
|
|
7232
7356
|
} catch (error) {
|
|
7357
|
+
if ((0, _mastra_core_storage.isRunFenceConflictError)(error)) throw error;
|
|
7233
7358
|
throw new _mastra_core_error.MastraError({
|
|
7234
7359
|
id: (0, _mastra_core_storage.createStorageErrorId)("MONGODB", "SAVE_MESSAGES", "FAILED"),
|
|
7235
7360
|
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
@@ -7237,49 +7362,51 @@ var MemoryStorageMongoDB = class MemoryStorageMongoDB extends _mastra_core_stora
|
|
|
7237
7362
|
}, error);
|
|
7238
7363
|
}
|
|
7239
7364
|
}
|
|
7240
|
-
async updateMessages({ messages }) {
|
|
7365
|
+
async updateMessages({ messages, fence }) {
|
|
7241
7366
|
if (messages.length === 0) return [];
|
|
7242
7367
|
const messageIds = messages.map((m) => m.id);
|
|
7243
7368
|
const collection = await this.getCollection(_mastra_core_storage.TABLE_MESSAGES);
|
|
7244
|
-
|
|
7245
|
-
|
|
7246
|
-
|
|
7247
|
-
|
|
7248
|
-
|
|
7249
|
-
const
|
|
7250
|
-
|
|
7251
|
-
|
|
7252
|
-
|
|
7253
|
-
|
|
7254
|
-
|
|
7255
|
-
|
|
7256
|
-
|
|
7257
|
-
|
|
7258
|
-
|
|
7259
|
-
|
|
7260
|
-
|
|
7261
|
-
|
|
7262
|
-
...existingMessage.content.metadata
|
|
7263
|
-
|
|
7264
|
-
|
|
7265
|
-
|
|
7266
|
-
|
|
7267
|
-
|
|
7268
|
-
|
|
7269
|
-
|
|
7270
|
-
const
|
|
7271
|
-
|
|
7272
|
-
|
|
7273
|
-
|
|
7369
|
+
return withRunFence(this.#connector, this.#runFenceCheck(fence, "updateMessages"), async (session) => {
|
|
7370
|
+
const existingMessagesParsed = (await collection.find({ id: { $in: messageIds } }, { session }).toArray()).map((msg) => this.parseRow(msg));
|
|
7371
|
+
if (existingMessagesParsed.length === 0) return [];
|
|
7372
|
+
const threadIdsToUpdate = /* @__PURE__ */ new Set();
|
|
7373
|
+
const bulkOps = [];
|
|
7374
|
+
for (const existingMessage of existingMessagesParsed) {
|
|
7375
|
+
const updatePayload = messages.find((m) => m.id === existingMessage.id);
|
|
7376
|
+
if (!updatePayload) continue;
|
|
7377
|
+
const { id, ...fieldsToUpdate } = updatePayload;
|
|
7378
|
+
if (Object.keys(fieldsToUpdate).length === 0) continue;
|
|
7379
|
+
threadIdsToUpdate.add(existingMessage.threadId);
|
|
7380
|
+
if (updatePayload.threadId && updatePayload.threadId !== existingMessage.threadId) threadIdsToUpdate.add(updatePayload.threadId);
|
|
7381
|
+
const updateDoc = {};
|
|
7382
|
+
const updatableFields = { ...fieldsToUpdate };
|
|
7383
|
+
if (updatableFields.content) {
|
|
7384
|
+
const newContent = {
|
|
7385
|
+
...existingMessage.content,
|
|
7386
|
+
...updatableFields.content,
|
|
7387
|
+
...existingMessage.content?.metadata && updatableFields.content.metadata ? { metadata: {
|
|
7388
|
+
...existingMessage.content.metadata,
|
|
7389
|
+
...updatableFields.content.metadata
|
|
7390
|
+
} } : {}
|
|
7391
|
+
};
|
|
7392
|
+
updateDoc.content = JSON.stringify(newContent);
|
|
7393
|
+
delete updatableFields.content;
|
|
7394
|
+
}
|
|
7395
|
+
for (const key in updatableFields) if (Object.prototype.hasOwnProperty.call(updatableFields, key)) {
|
|
7396
|
+
const dbKey = key === "threadId" ? "thread_id" : key;
|
|
7397
|
+
let value = updatableFields[key];
|
|
7398
|
+
if (typeof value === "object" && value !== null) value = JSON.stringify(value);
|
|
7399
|
+
updateDoc[dbKey] = value;
|
|
7400
|
+
}
|
|
7401
|
+
if (Object.keys(updateDoc).length > 0) bulkOps.push({ updateOne: {
|
|
7402
|
+
filter: { id },
|
|
7403
|
+
update: { $set: updateDoc }
|
|
7404
|
+
} });
|
|
7274
7405
|
}
|
|
7275
|
-
if (
|
|
7276
|
-
|
|
7277
|
-
|
|
7278
|
-
|
|
7279
|
-
}
|
|
7280
|
-
if (bulkOps.length > 0) await collection.bulkWrite(bulkOps);
|
|
7281
|
-
if (threadIdsToUpdate.size > 0) await (await this.getCollection(_mastra_core_storage.TABLE_THREADS)).updateMany({ id: { $in: Array.from(threadIdsToUpdate) } }, { $set: { updatedAt: /* @__PURE__ */ new Date() } });
|
|
7282
|
-
return (await collection.find({ id: { $in: messageIds } }).toArray()).map((row) => this.parseRow(row));
|
|
7406
|
+
if (bulkOps.length > 0) await collection.bulkWrite(bulkOps, { session });
|
|
7407
|
+
if (threadIdsToUpdate.size > 0) await (await this.getCollection(_mastra_core_storage.TABLE_THREADS)).updateMany({ id: { $in: Array.from(threadIdsToUpdate) } }, { $set: { updatedAt: /* @__PURE__ */ new Date() } }, { session });
|
|
7408
|
+
return (await collection.find({ id: { $in: messageIds } }, { session }).toArray()).map((row) => this.parseRow(row));
|
|
7409
|
+
});
|
|
7283
7410
|
}
|
|
7284
7411
|
async getResourceById({ resourceId }) {
|
|
7285
7412
|
try {
|
|
@@ -7314,9 +7441,11 @@ var MemoryStorageMongoDB = class MemoryStorageMongoDB extends _mastra_core_stora
|
|
|
7314
7441
|
}, error);
|
|
7315
7442
|
}
|
|
7316
7443
|
}
|
|
7317
|
-
async updateResource({ resourceId, workingMemory, metadata }) {
|
|
7444
|
+
async updateResource({ resourceId, workingMemory, metadata, fence }) {
|
|
7318
7445
|
try {
|
|
7446
|
+
const check = this.#runFenceCheck(fence, "updateResource");
|
|
7319
7447
|
const existingResource = await this.getResourceById({ resourceId });
|
|
7448
|
+
const collection = await this.getCollection(_mastra_core_storage.TABLE_RESOURCES);
|
|
7320
7449
|
if (!existingResource) {
|
|
7321
7450
|
const newResource = {
|
|
7322
7451
|
id: resourceId,
|
|
@@ -7325,7 +7454,11 @@ var MemoryStorageMongoDB = class MemoryStorageMongoDB extends _mastra_core_stora
|
|
|
7325
7454
|
createdAt: /* @__PURE__ */ new Date(),
|
|
7326
7455
|
updatedAt: /* @__PURE__ */ new Date()
|
|
7327
7456
|
};
|
|
7328
|
-
|
|
7457
|
+
await withRunFence(this.#connector, check, (session) => collection.updateOne({ id: resourceId }, { $set: { ...newResource } }, {
|
|
7458
|
+
upsert: true,
|
|
7459
|
+
session
|
|
7460
|
+
}));
|
|
7461
|
+
return newResource;
|
|
7329
7462
|
}
|
|
7330
7463
|
const updatedResource = {
|
|
7331
7464
|
...existingResource,
|
|
@@ -7336,13 +7469,13 @@ var MemoryStorageMongoDB = class MemoryStorageMongoDB extends _mastra_core_stora
|
|
|
7336
7469
|
} : existingResource.metadata,
|
|
7337
7470
|
updatedAt: /* @__PURE__ */ new Date()
|
|
7338
7471
|
};
|
|
7339
|
-
const collection = await this.getCollection(_mastra_core_storage.TABLE_RESOURCES);
|
|
7340
7472
|
const updateDoc = { updatedAt: updatedResource.updatedAt };
|
|
7341
7473
|
if (workingMemory !== void 0) updateDoc.workingMemory = workingMemory;
|
|
7342
7474
|
if (metadata) updateDoc.metadata = updatedResource.metadata;
|
|
7343
|
-
await collection.updateOne({ id: resourceId }, { $set: updateDoc });
|
|
7475
|
+
await withRunFence(this.#connector, check, (session) => collection.updateOne({ id: resourceId }, { $set: updateDoc }, { session }));
|
|
7344
7476
|
return updatedResource;
|
|
7345
7477
|
} catch (error) {
|
|
7478
|
+
if ((0, _mastra_core_storage.isRunFenceConflictError)(error)) throw error;
|
|
7346
7479
|
throw new _mastra_core_error.MastraError({
|
|
7347
7480
|
id: (0, _mastra_core_storage.createStorageErrorId)("MONGODB", "UPDATE_RESOURCE", "FAILED"),
|
|
7348
7481
|
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
@@ -7442,14 +7575,19 @@ var MemoryStorageMongoDB = class MemoryStorageMongoDB extends _mastra_core_stora
|
|
|
7442
7575
|
throw mastraError;
|
|
7443
7576
|
}
|
|
7444
7577
|
}
|
|
7445
|
-
async saveThread({ thread }) {
|
|
7578
|
+
async saveThread({ thread, fence }) {
|
|
7446
7579
|
try {
|
|
7447
|
-
|
|
7580
|
+
const collection = await this.getCollection(_mastra_core_storage.TABLE_THREADS);
|
|
7581
|
+
await withRunFence(this.#connector, this.#runFenceCheck(fence, "saveThread"), (session) => collection.updateOne({ id: thread.id }, { $set: {
|
|
7448
7582
|
...thread,
|
|
7449
7583
|
metadata: thread.metadata
|
|
7450
|
-
} }, {
|
|
7584
|
+
} }, {
|
|
7585
|
+
upsert: true,
|
|
7586
|
+
session
|
|
7587
|
+
}));
|
|
7451
7588
|
return thread;
|
|
7452
7589
|
} catch (error) {
|
|
7590
|
+
if ((0, _mastra_core_storage.isRunFenceConflictError)(error)) throw error;
|
|
7453
7591
|
throw new _mastra_core_error.MastraError({
|
|
7454
7592
|
id: (0, _mastra_core_storage.createStorageErrorId)("MONGODB", "SAVE_THREAD", "FAILED"),
|
|
7455
7593
|
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
@@ -7458,7 +7596,8 @@ var MemoryStorageMongoDB = class MemoryStorageMongoDB extends _mastra_core_stora
|
|
|
7458
7596
|
}, error);
|
|
7459
7597
|
}
|
|
7460
7598
|
}
|
|
7461
|
-
async updateThread({ id, title, metadata }) {
|
|
7599
|
+
async updateThread({ id, title, metadata, fence }) {
|
|
7600
|
+
const check = this.#runFenceCheck(fence, "updateThread");
|
|
7462
7601
|
const thread = await this.getThreadById({ threadId: id });
|
|
7463
7602
|
if (!thread) throw new _mastra_core_error.MastraError({
|
|
7464
7603
|
id: (0, _mastra_core_storage.createStorageErrorId)("MONGODB", "UPDATE_THREAD", "NOT_FOUND"),
|
|
@@ -7481,12 +7620,14 @@ var MemoryStorageMongoDB = class MemoryStorageMongoDB extends _mastra_core_stora
|
|
|
7481
7620
|
updatedAt: now
|
|
7482
7621
|
};
|
|
7483
7622
|
try {
|
|
7484
|
-
|
|
7623
|
+
const collection = await this.getCollection(_mastra_core_storage.TABLE_THREADS);
|
|
7624
|
+
await withRunFence(this.#connector, check, (session) => collection.updateOne({ id }, { $set: {
|
|
7485
7625
|
title: updatedThread.title,
|
|
7486
7626
|
metadata: updatedThread.metadata,
|
|
7487
7627
|
updatedAt: now
|
|
7488
|
-
} });
|
|
7628
|
+
} }, { session }));
|
|
7489
7629
|
} catch (error) {
|
|
7630
|
+
if ((0, _mastra_core_storage.isRunFenceConflictError)(error)) throw error;
|
|
7490
7631
|
throw new _mastra_core_error.MastraError({
|
|
7491
7632
|
id: (0, _mastra_core_storage.createStorageErrorId)("MONGODB", "UPDATE_THREAD", "FAILED"),
|
|
7492
7633
|
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
@@ -7509,16 +7650,19 @@ var MemoryStorageMongoDB = class MemoryStorageMongoDB extends _mastra_core_stora
|
|
|
7509
7650
|
}, error);
|
|
7510
7651
|
}
|
|
7511
7652
|
}
|
|
7512
|
-
async deleteMessages(messageIds) {
|
|
7653
|
+
async deleteMessages(messageIds, options) {
|
|
7513
7654
|
if (messageIds.length === 0) return;
|
|
7514
7655
|
try {
|
|
7515
7656
|
const messagesCollection = await this.getCollection(_mastra_core_storage.TABLE_MESSAGES);
|
|
7516
7657
|
const threadsCollection = await this.getCollection(_mastra_core_storage.TABLE_THREADS);
|
|
7517
|
-
|
|
7518
|
-
|
|
7519
|
-
|
|
7520
|
-
|
|
7658
|
+
await withRunFence(this.#connector, this.#runFenceCheck(options?.fence, "deleteMessages"), async (session) => {
|
|
7659
|
+
const messagesToDelete = await messagesCollection.find({ id: { $in: messageIds } }, { session }).toArray();
|
|
7660
|
+
const threadIds = [...new Set(messagesToDelete.map((m) => m.thread_id))];
|
|
7661
|
+
await messagesCollection.deleteMany({ id: { $in: messageIds } }, { session });
|
|
7662
|
+
if (threadIds.length > 0) await threadsCollection.updateMany({ id: { $in: threadIds } }, { $set: { updatedAt: /* @__PURE__ */ new Date() } }, { session });
|
|
7663
|
+
});
|
|
7521
7664
|
} catch (error) {
|
|
7665
|
+
if ((0, _mastra_core_storage.isRunFenceConflictError)(error)) throw error;
|
|
7522
7666
|
throw new _mastra_core_error.MastraError({
|
|
7523
7667
|
id: (0, _mastra_core_storage.createStorageErrorId)("MONGODB", "DELETE_MESSAGES", "FAILED"),
|
|
7524
7668
|
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
@@ -7885,7 +8029,7 @@ var MemoryStorageMongoDB = class MemoryStorageMongoDB extends _mastra_core_stora
|
|
|
7885
8029
|
applied: false,
|
|
7886
8030
|
reason: "conflict"
|
|
7887
8031
|
};
|
|
7888
|
-
if ((await collection.updateOne({
|
|
8032
|
+
if ((await withRunFence(this.#connector, this.#runFenceCheck(void 0, "updateActiveObservations"), (session) => collection.updateOne({
|
|
7889
8033
|
id: input.id,
|
|
7890
8034
|
supersededBy: null,
|
|
7891
8035
|
...matchStoredFields(doc, ["activeObservations", "lastObservedAt"])
|
|
@@ -7899,7 +8043,7 @@ var MemoryStorageMongoDB = class MemoryStorageMongoDB extends _mastra_core_stora
|
|
|
7899
8043
|
updatedAt: /* @__PURE__ */ new Date()
|
|
7900
8044
|
},
|
|
7901
8045
|
$inc: { totalTokensObserved: safeTokenCount }
|
|
7902
|
-
})).matchedCount === 1) return { applied: true };
|
|
8046
|
+
}, { session }))).matchedCount === 1) return { applied: true };
|
|
7903
8047
|
}
|
|
7904
8048
|
throw omConflict("UPDATE_ACTIVE_OBSERVATIONS", input.id);
|
|
7905
8049
|
} catch (error) {
|
|
@@ -7915,7 +8059,7 @@ var MemoryStorageMongoDB = class MemoryStorageMongoDB extends _mastra_core_stora
|
|
|
7915
8059
|
async createReflectionGeneration(input) {
|
|
7916
8060
|
try {
|
|
7917
8061
|
const { currentRecord } = input;
|
|
7918
|
-
return await this.#rollOver(currentRecord, (doc) => {
|
|
8062
|
+
return await this.#rollOver(currentRecord, "createReflectionGeneration", (doc) => {
|
|
7919
8063
|
const stored = this.parseOMDocument(doc);
|
|
7920
8064
|
const plan = planReflectionGenerationText({
|
|
7921
8065
|
storedObservations: stored.activeObservations,
|
|
@@ -8152,7 +8296,7 @@ var MemoryStorageMongoDB = class MemoryStorageMongoDB extends _mastra_core_stora
|
|
|
8152
8296
|
let hops = 0;
|
|
8153
8297
|
let retries = 0;
|
|
8154
8298
|
for (;;) {
|
|
8155
|
-
if ((await collection.updateOne({
|
|
8299
|
+
if ((await withRunFence(this.#connector, this.#runFenceCheck(void 0, "updateBufferedObservations"), (session) => collection.updateOne({
|
|
8156
8300
|
id: targetId,
|
|
8157
8301
|
supersededBy: null,
|
|
8158
8302
|
"bufferedObservationChunks.cycleId": { $ne: input.chunk.cycleId },
|
|
@@ -8166,7 +8310,7 @@ var MemoryStorageMongoDB = class MemoryStorageMongoDB extends _mastra_core_stora
|
|
|
8166
8310
|
bufferedObservationChunks: { $concatArrays: [{ $ifNull: ["$bufferedObservationChunks", []] }, { $literal: [newChunk] }] },
|
|
8167
8311
|
...lastBufferedAtTime ? { lastBufferedAtTime: { $max: ["$lastBufferedAtTime", { $literal: lastBufferedAtTime }] } } : {},
|
|
8168
8312
|
updatedAt: { $literal: /* @__PURE__ */ new Date() }
|
|
8169
|
-
} }])).matchedCount === 1) return {
|
|
8313
|
+
} }], { session }))).matchedCount === 1) return {
|
|
8170
8314
|
persisted: true,
|
|
8171
8315
|
recordId: targetId
|
|
8172
8316
|
};
|
|
@@ -8189,7 +8333,7 @@ var MemoryStorageMongoDB = class MemoryStorageMongoDB extends _mastra_core_stora
|
|
|
8189
8333
|
recordId: targetId
|
|
8190
8334
|
};
|
|
8191
8335
|
if (stored !== void 0 && stored !== null && !Array.isArray(stored)) {
|
|
8192
|
-
if ((await collection.updateOne({
|
|
8336
|
+
if ((await withRunFence(this.#connector, this.#runFenceCheck(void 0, "updateBufferedObservations"), (session) => collection.updateOne({
|
|
8193
8337
|
id: targetId,
|
|
8194
8338
|
supersededBy: null,
|
|
8195
8339
|
bufferedObservationChunks: stored,
|
|
@@ -8198,7 +8342,7 @@ var MemoryStorageMongoDB = class MemoryStorageMongoDB extends _mastra_core_stora
|
|
|
8198
8342
|
bufferedObservationChunks: [newChunk],
|
|
8199
8343
|
...lastBufferedAtTime ? { lastBufferedAtTime: maxObservationCursor(doc.lastBufferedAtTime, lastBufferedAtTime) } : {},
|
|
8200
8344
|
updatedAt: /* @__PURE__ */ new Date()
|
|
8201
|
-
} })).matchedCount === 1) return {
|
|
8345
|
+
} }, { session }))).matchedCount === 1) return {
|
|
8202
8346
|
persisted: true,
|
|
8203
8347
|
recordId: targetId
|
|
8204
8348
|
};
|
|
@@ -8288,7 +8432,7 @@ var MemoryStorageMongoDB = class MemoryStorageMongoDB extends _mastra_core_stora
|
|
|
8288
8432
|
const newTokenCount = existingTokenCount + activatedTokens;
|
|
8289
8433
|
const existingPending = Number(doc.pendingMessageTokens || 0);
|
|
8290
8434
|
const newPending = Math.max(0, existingPending - activatedMessageTokens);
|
|
8291
|
-
if ((await collection.updateOne({
|
|
8435
|
+
if ((await withRunFence(this.#connector, this.#runFenceCheck(void 0, "swapBufferedToActive"), (session) => collection.updateOne({
|
|
8292
8436
|
id: input.id,
|
|
8293
8437
|
supersededBy: null,
|
|
8294
8438
|
...matchStoredFields(doc, [
|
|
@@ -8305,7 +8449,7 @@ var MemoryStorageMongoDB = class MemoryStorageMongoDB extends _mastra_core_stora
|
|
|
8305
8449
|
bufferedObservationChunks: remainingChunks,
|
|
8306
8450
|
lastObservedAt: maxObservationCursor(doc.lastObservedAt, lastObservedAt),
|
|
8307
8451
|
updatedAt: /* @__PURE__ */ new Date()
|
|
8308
|
-
} })).matchedCount === 0) continue;
|
|
8452
|
+
} }, { session }))).matchedCount === 0) continue;
|
|
8309
8453
|
const latestChunkHints = activatedChunks[activatedChunks.length - 1];
|
|
8310
8454
|
return {
|
|
8311
8455
|
chunksActivated: activatedChunks.length,
|
|
@@ -8354,13 +8498,13 @@ var MemoryStorageMongoDB = class MemoryStorageMongoDB extends _mastra_core_stora
|
|
|
8354
8498
|
const newContent = existingContent ? `${existingContent}\n\n${input.reflection}` : input.reflection;
|
|
8355
8499
|
const newTokens = existingTokens + input.tokenCount;
|
|
8356
8500
|
const newInputTokens = existingInputTokens + input.inputTokenCount;
|
|
8357
|
-
if ((await collection.updateOne({ id: input.id }, { $set: {
|
|
8501
|
+
if ((await withRunFence(this.#connector, this.#runFenceCheck(void 0, "updateBufferedReflection"), (session) => collection.updateOne({ id: input.id }, { $set: {
|
|
8358
8502
|
bufferedReflection: newContent,
|
|
8359
8503
|
bufferedReflectionTokens: newTokens,
|
|
8360
8504
|
bufferedReflectionInputTokens: newInputTokens,
|
|
8361
8505
|
reflectedObservationLineCount: input.reflectedObservationLineCount,
|
|
8362
8506
|
updatedAt: /* @__PURE__ */ new Date()
|
|
8363
|
-
} })).matchedCount === 0) throw new _mastra_core_error.MastraError({
|
|
8507
|
+
} }, { session }))).matchedCount === 0) throw new _mastra_core_error.MastraError({
|
|
8364
8508
|
id: (0, _mastra_core_storage.createStorageErrorId)("MONGODB", "UPDATE_BUFFERED_REFLECTION", "NOT_FOUND"),
|
|
8365
8509
|
text: `Observational memory record not found: ${input.id}`,
|
|
8366
8510
|
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
@@ -8380,7 +8524,7 @@ var MemoryStorageMongoDB = class MemoryStorageMongoDB extends _mastra_core_stora
|
|
|
8380
8524
|
async swapBufferedReflectionToActive(input) {
|
|
8381
8525
|
try {
|
|
8382
8526
|
const { currentRecord } = input;
|
|
8383
|
-
return await this.#rollOver(currentRecord, (doc) => {
|
|
8527
|
+
return await this.#rollOver(currentRecord, "swapBufferedReflectionToActive", (doc) => {
|
|
8384
8528
|
const stored = this.parseOMDocument(doc);
|
|
8385
8529
|
const bufferedReflection = stored.bufferedReflection || "";
|
|
8386
8530
|
if (!bufferedReflection) throw new _mastra_core_error.MastraError({
|
|
@@ -8466,7 +8610,7 @@ var MemoryStorageMongoDB = class MemoryStorageMongoDB extends _mastra_core_stora
|
|
|
8466
8610
|
*
|
|
8467
8611
|
* A crash between 2 and 3 is finished by the next head read (`#getHeadDoc`) or startup.
|
|
8468
8612
|
*/
|
|
8469
|
-
async #rollOver(currentRecord, decide) {
|
|
8613
|
+
async #rollOver(currentRecord, operation, decide) {
|
|
8470
8614
|
const collection = await this.getCollection(OM_TABLE);
|
|
8471
8615
|
for (let attempt = 1; attempt <= OM_MAX_CONDITIONAL_ATTEMPTS; attempt++) {
|
|
8472
8616
|
const doc = await collection.findOne({ id: currentRecord.id });
|
|
@@ -8477,7 +8621,7 @@ var MemoryStorageMongoDB = class MemoryStorageMongoDB extends _mastra_core_stora
|
|
|
8477
8621
|
}
|
|
8478
8622
|
const pending = decide(doc);
|
|
8479
8623
|
if (!pending) return this.parseOMDocument(doc);
|
|
8480
|
-
const frozen = await collection.findOneAndUpdate({
|
|
8624
|
+
const frozen = await withRunFence(this.#connector, this.#runFenceCheck(void 0, operation), (session) => collection.findOneAndUpdate({
|
|
8481
8625
|
id: doc.id,
|
|
8482
8626
|
supersededBy: null,
|
|
8483
8627
|
...matchStoredFields(doc, [
|
|
@@ -8489,7 +8633,10 @@ var MemoryStorageMongoDB = class MemoryStorageMongoDB extends _mastra_core_stora
|
|
|
8489
8633
|
}, { $set: {
|
|
8490
8634
|
supersededBy: pending.newId,
|
|
8491
8635
|
pendingSuccessor: pending
|
|
8492
|
-
} }, {
|
|
8636
|
+
} }, {
|
|
8637
|
+
returnDocument: "before",
|
|
8638
|
+
session
|
|
8639
|
+
}));
|
|
8493
8640
|
if (!frozen) continue;
|
|
8494
8641
|
return this.parseOMDocument(await this.#completeRollover(collection, frozen, pending));
|
|
8495
8642
|
}
|
|
@@ -11804,33 +11951,58 @@ var MongoDBWorkflowDefinitionsStore = class MongoDBWorkflowDefinitionsStore exte
|
|
|
11804
11951
|
};
|
|
11805
11952
|
//#endregion
|
|
11806
11953
|
//#region src/storage/domains/workflows/index.ts
|
|
11954
|
+
const RUN_OWNER_PROJECTION = {
|
|
11955
|
+
generation: 1,
|
|
11956
|
+
ownerId: 1,
|
|
11957
|
+
leaseExpiresAt: 1,
|
|
11958
|
+
live: { $gt: ["$leaseExpiresAt", "$$NOW"] }
|
|
11959
|
+
};
|
|
11960
|
+
const NOT_LIVE = { $or: [{ leaseExpiresAt: null }, { $expr: { $lte: ["$leaseExpiresAt", "$$NOW"] } }] };
|
|
11961
|
+
function toRunOwnershipRecord(doc) {
|
|
11962
|
+
return {
|
|
11963
|
+
runId: doc._id,
|
|
11964
|
+
generation: Number(doc.generation),
|
|
11965
|
+
ownerId: doc.ownerId,
|
|
11966
|
+
leaseExpiresAt: doc.leaseExpiresAt ?? null,
|
|
11967
|
+
live: Boolean(doc.live)
|
|
11968
|
+
};
|
|
11969
|
+
}
|
|
11807
11970
|
var WorkflowsStorageMongoDB = class WorkflowsStorageMongoDB extends _mastra_core_storage.WorkflowsStorage {
|
|
11808
11971
|
#connector;
|
|
11809
11972
|
#skipDefaultIndexes;
|
|
11810
11973
|
#indexes;
|
|
11811
11974
|
/** Collections managed by this domain */
|
|
11812
|
-
static MANAGED_COLLECTIONS = [_mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT];
|
|
11975
|
+
static MANAGED_COLLECTIONS = [_mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT, _mastra_core_storage.TABLE_WORKFLOW_RUN_OWNERS];
|
|
11813
11976
|
/**
|
|
11814
|
-
*
|
|
11815
|
-
* a run is pruned only after its snapshot has not been touched
|
|
11977
|
+
* Both anchors are `updatedAt` (BSON date), so the policies read as
|
|
11978
|
+
* inactivity: a run is pruned only after its snapshot has not been touched
|
|
11979
|
+
* for `maxAge`, and an ownership document only after no claim, renewal or
|
|
11980
|
+
* release has touched it for `maxAge`.
|
|
11816
11981
|
*/
|
|
11817
|
-
static retentionTables = {
|
|
11818
|
-
|
|
11819
|
-
|
|
11820
|
-
|
|
11821
|
-
|
|
11982
|
+
static retentionTables = {
|
|
11983
|
+
workflowSnapshot: {
|
|
11984
|
+
table: _mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT,
|
|
11985
|
+
column: "updatedAt",
|
|
11986
|
+
indexed: true
|
|
11987
|
+
},
|
|
11988
|
+
runOwnership: {
|
|
11989
|
+
table: _mastra_core_storage.TABLE_WORKFLOW_RUN_OWNERS,
|
|
11990
|
+
column: "updatedAt",
|
|
11991
|
+
indexed: true
|
|
11992
|
+
}
|
|
11993
|
+
};
|
|
11822
11994
|
constructor(config) {
|
|
11823
11995
|
super();
|
|
11824
11996
|
this.#connector = resolveMongoDBConfig(config);
|
|
11825
11997
|
this.#skipDefaultIndexes = config.skipDefaultIndexes;
|
|
11826
11998
|
this.#indexes = config.indexes?.filter((idx) => WorkflowsStorageMongoDB.MANAGED_COLLECTIONS.includes(idx.collection));
|
|
11827
11999
|
}
|
|
11828
|
-
/** Delete workflow snapshots idle for longer than
|
|
12000
|
+
/** Delete workflow snapshots and ownership documents idle for longer than each policy's `maxAge`, batched. */
|
|
11829
12001
|
async prune(policies, options) {
|
|
11830
12002
|
const targets = resolveTargets({
|
|
11831
12003
|
policies,
|
|
11832
12004
|
descriptor: WorkflowsStorageMongoDB.retentionTables,
|
|
11833
|
-
order: ["workflowSnapshot"]
|
|
12005
|
+
order: ["workflowSnapshot", "runOwnership"]
|
|
11834
12006
|
});
|
|
11835
12007
|
return runPrune({
|
|
11836
12008
|
connector: this.#connector,
|
|
@@ -11843,6 +12015,13 @@ var WorkflowsStorageMongoDB = class WorkflowsStorageMongoDB extends _mastra_core
|
|
|
11843
12015
|
supportsConcurrentUpdates() {
|
|
11844
12016
|
return true;
|
|
11845
12017
|
}
|
|
12018
|
+
/**
|
|
12019
|
+
* Fenced writes need multi-document transactions, so only replica sets and
|
|
12020
|
+
* sharded clusters fence. Rejects while the deployment can't be probed.
|
|
12021
|
+
*/
|
|
12022
|
+
supportsRunFencing() {
|
|
12023
|
+
return this.#connector.probeTransactions();
|
|
12024
|
+
}
|
|
11846
12025
|
async getCollection(name) {
|
|
11847
12026
|
return this.#connector.getCollection(name);
|
|
11848
12027
|
}
|
|
@@ -11850,6 +12029,124 @@ var WorkflowsStorageMongoDB = class WorkflowsStorageMongoDB extends _mastra_core
|
|
|
11850
12029
|
await this.createDefaultIndexes();
|
|
11851
12030
|
await this.createCustomIndexes();
|
|
11852
12031
|
}
|
|
12032
|
+
#runFenceCheck(fence, runId, operation) {
|
|
12033
|
+
const resolved = (0, _mastra_core_storage.resolveRunFence)(this, fence, runId);
|
|
12034
|
+
return resolved && {
|
|
12035
|
+
claims: _mastra_core_storage.TABLE_WORKFLOW_RUN_OWNERS,
|
|
12036
|
+
fence: resolved,
|
|
12037
|
+
operation
|
|
12038
|
+
};
|
|
12039
|
+
}
|
|
12040
|
+
async #readRunOwner(runId) {
|
|
12041
|
+
const doc = await (await getRunClaims(this.#connector, _mastra_core_storage.TABLE_WORKFLOW_RUN_OWNERS)).findOne({ _id: runId }, { projection: RUN_OWNER_PROJECTION });
|
|
12042
|
+
return doc ? toRunOwnershipRecord(doc) : null;
|
|
12043
|
+
}
|
|
12044
|
+
#ownershipError(operation, runId, error) {
|
|
12045
|
+
return new _mastra_core_error.MastraError({
|
|
12046
|
+
id: (0, _mastra_core_storage.createStorageErrorId)("MONGODB", operation, "FAILED"),
|
|
12047
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
12048
|
+
category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
|
|
12049
|
+
details: { runId }
|
|
12050
|
+
}, error);
|
|
12051
|
+
}
|
|
12052
|
+
async claimRunOwnership({ runId, ownerId, leaseMs, force, expectedGeneration }) {
|
|
12053
|
+
try {
|
|
12054
|
+
const owners = await getRunClaims(this.#connector, _mastra_core_storage.TABLE_WORKFLOW_RUN_OWNERS);
|
|
12055
|
+
const claim = (generation) => [{ $set: {
|
|
12056
|
+
generation,
|
|
12057
|
+
ownerId: { $literal: ownerId },
|
|
12058
|
+
leaseExpiresAt: { $add: ["$$NOW", leaseMs] },
|
|
12059
|
+
updatedAt: "$$NOW"
|
|
12060
|
+
} }];
|
|
12061
|
+
if (!expectedGeneration) {
|
|
12062
|
+
try {
|
|
12063
|
+
const created = await owners.findOneAndUpdate({
|
|
12064
|
+
_id: runId,
|
|
12065
|
+
generation: { $exists: false }
|
|
12066
|
+
}, claim({ $max: [1, { $toLong: "$$NOW" }] }), {
|
|
12067
|
+
upsert: true,
|
|
12068
|
+
returnDocument: "after",
|
|
12069
|
+
projection: RUN_OWNER_PROJECTION
|
|
12070
|
+
});
|
|
12071
|
+
if (created) return {
|
|
12072
|
+
acquired: true,
|
|
12073
|
+
record: toRunOwnershipRecord(created)
|
|
12074
|
+
};
|
|
12075
|
+
} catch (error) {
|
|
12076
|
+
if (!isDuplicateKeyError(error)) throw error;
|
|
12077
|
+
}
|
|
12078
|
+
if (expectedGeneration === 0) return {
|
|
12079
|
+
acquired: false,
|
|
12080
|
+
record: await this.#readRunOwner(runId)
|
|
12081
|
+
};
|
|
12082
|
+
}
|
|
12083
|
+
const advanced = await owners.findOneAndUpdate({
|
|
12084
|
+
_id: runId,
|
|
12085
|
+
...expectedGeneration !== void 0 ? { generation: expectedGeneration } : {},
|
|
12086
|
+
...force ? {} : NOT_LIVE
|
|
12087
|
+
}, claim({ $add: ["$generation", 1] }), {
|
|
12088
|
+
returnDocument: "after",
|
|
12089
|
+
projection: RUN_OWNER_PROJECTION
|
|
12090
|
+
});
|
|
12091
|
+
if (advanced) return {
|
|
12092
|
+
acquired: true,
|
|
12093
|
+
record: toRunOwnershipRecord(advanced)
|
|
12094
|
+
};
|
|
12095
|
+
return {
|
|
12096
|
+
acquired: false,
|
|
12097
|
+
record: await this.#readRunOwner(runId)
|
|
12098
|
+
};
|
|
12099
|
+
} catch (error) {
|
|
12100
|
+
throw this.#ownershipError("CLAIM_RUN_OWNERSHIP", runId, error);
|
|
12101
|
+
}
|
|
12102
|
+
}
|
|
12103
|
+
async renewRunOwnership({ leaseMs, ...fence }) {
|
|
12104
|
+
try {
|
|
12105
|
+
const renewed = await (await getRunClaims(this.#connector, _mastra_core_storage.TABLE_WORKFLOW_RUN_OWNERS)).findOneAndUpdate({
|
|
12106
|
+
_id: fence.runId,
|
|
12107
|
+
generation: fence.generation,
|
|
12108
|
+
ownerId: fence.ownerId,
|
|
12109
|
+
leaseExpiresAt: { $ne: null }
|
|
12110
|
+
}, [{ $set: {
|
|
12111
|
+
leaseExpiresAt: { $add: ["$$NOW", leaseMs] },
|
|
12112
|
+
updatedAt: "$$NOW"
|
|
12113
|
+
} }], {
|
|
12114
|
+
returnDocument: "after",
|
|
12115
|
+
projection: RUN_OWNER_PROJECTION
|
|
12116
|
+
});
|
|
12117
|
+
if (renewed) return {
|
|
12118
|
+
renewed: true,
|
|
12119
|
+
record: toRunOwnershipRecord(renewed)
|
|
12120
|
+
};
|
|
12121
|
+
return {
|
|
12122
|
+
renewed: false,
|
|
12123
|
+
record: await this.#readRunOwner(fence.runId)
|
|
12124
|
+
};
|
|
12125
|
+
} catch (error) {
|
|
12126
|
+
throw this.#ownershipError("RENEW_RUN_OWNERSHIP", fence.runId, error);
|
|
12127
|
+
}
|
|
12128
|
+
}
|
|
12129
|
+
async releaseRunOwnership(fence) {
|
|
12130
|
+
try {
|
|
12131
|
+
return (await (await getRunClaims(this.#connector, _mastra_core_storage.TABLE_WORKFLOW_RUN_OWNERS)).updateOne({
|
|
12132
|
+
_id: fence.runId,
|
|
12133
|
+
generation: fence.generation,
|
|
12134
|
+
ownerId: fence.ownerId
|
|
12135
|
+
}, [{ $set: {
|
|
12136
|
+
leaseExpiresAt: null,
|
|
12137
|
+
updatedAt: "$$NOW"
|
|
12138
|
+
} }])).matchedCount > 0;
|
|
12139
|
+
} catch (error) {
|
|
12140
|
+
throw this.#ownershipError("RELEASE_RUN_OWNERSHIP", fence.runId, error);
|
|
12141
|
+
}
|
|
12142
|
+
}
|
|
12143
|
+
async getRunOwnership({ runId }) {
|
|
12144
|
+
try {
|
|
12145
|
+
return await this.#readRunOwner(runId);
|
|
12146
|
+
} catch (error) {
|
|
12147
|
+
throw this.#ownershipError("GET_RUN_OWNERSHIP", runId, error);
|
|
12148
|
+
}
|
|
12149
|
+
}
|
|
11853
12150
|
/**
|
|
11854
12151
|
* Returns default index definitions for the workflows domain collections.
|
|
11855
12152
|
*/
|
|
@@ -11909,8 +12206,10 @@ var WorkflowsStorageMongoDB = class WorkflowsStorageMongoDB extends _mastra_core
|
|
|
11909
12206
|
}
|
|
11910
12207
|
async dangerouslyClearAll() {
|
|
11911
12208
|
await (await this.getCollection(_mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT)).deleteMany({});
|
|
12209
|
+
await (await this.getCollection(_mastra_core_storage.TABLE_WORKFLOW_RUN_OWNERS)).deleteMany({});
|
|
11912
12210
|
}
|
|
11913
|
-
async updateWorkflowResults({ workflowName, runId, stepId, result, requestContext, state }) {
|
|
12211
|
+
async updateWorkflowResults({ workflowName, runId, stepId, result, requestContext, state, fence }) {
|
|
12212
|
+
const check = this.#runFenceCheck(fence, runId, "updateWorkflowResults");
|
|
11914
12213
|
try {
|
|
11915
12214
|
const collection = await this.getCollection(_mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT);
|
|
11916
12215
|
const now = /* @__PURE__ */ new Date();
|
|
@@ -11930,7 +12229,7 @@ var WorkflowsStorageMongoDB = class WorkflowsStorageMongoDB extends _mastra_core
|
|
|
11930
12229
|
runId,
|
|
11931
12230
|
requestContext: {}
|
|
11932
12231
|
};
|
|
11933
|
-
const updatedDoc = await collection.findOneAndUpdate({
|
|
12232
|
+
const updatedDoc = await withRunFence(this.#connector, check, (session) => collection.findOneAndUpdate({
|
|
11934
12233
|
workflow_name: workflowName,
|
|
11935
12234
|
run_id: runId
|
|
11936
12235
|
}, [{ $set: {
|
|
@@ -11945,10 +12244,12 @@ var WorkflowsStorageMongoDB = class WorkflowsStorageMongoDB extends _mastra_core
|
|
|
11945
12244
|
createdAt: { $ifNull: ["$createdAt", now] }
|
|
11946
12245
|
} }], {
|
|
11947
12246
|
upsert: true,
|
|
11948
|
-
returnDocument: "after"
|
|
11949
|
-
|
|
12247
|
+
returnDocument: "after",
|
|
12248
|
+
session
|
|
12249
|
+
}));
|
|
11950
12250
|
return (typeof updatedDoc?.snapshot === "string" ? JSON.parse(updatedDoc.snapshot) : updatedDoc?.snapshot)?.context || {};
|
|
11951
12251
|
} catch (error) {
|
|
12252
|
+
if ((0, _mastra_core_storage.isRunFenceConflictError)(error)) throw error;
|
|
11952
12253
|
throw new _mastra_core_error.MastraError({
|
|
11953
12254
|
id: (0, _mastra_core_storage.createStorageErrorId)("MONGODB", "UPDATE_WORKFLOW_RESULTS", "FAILED"),
|
|
11954
12255
|
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
@@ -11961,7 +12262,8 @@ var WorkflowsStorageMongoDB = class WorkflowsStorageMongoDB extends _mastra_core
|
|
|
11961
12262
|
}, error);
|
|
11962
12263
|
}
|
|
11963
12264
|
}
|
|
11964
|
-
async updateWorkflowState({ workflowName, runId, opts }) {
|
|
12265
|
+
async updateWorkflowState({ workflowName, runId, opts, fence }) {
|
|
12266
|
+
const check = this.#runFenceCheck(fence, runId, "updateWorkflowState");
|
|
11965
12267
|
try {
|
|
11966
12268
|
const collection = await this.getCollection(_mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT);
|
|
11967
12269
|
const { expectedStatus, ...state } = opts;
|
|
@@ -11970,10 +12272,13 @@ var WorkflowsStorageMongoDB = class WorkflowsStorageMongoDB extends _mastra_core
|
|
|
11970
12272
|
run_id: runId
|
|
11971
12273
|
};
|
|
11972
12274
|
if (expectedStatus !== void 0) filter["snapshot.status"] = { $in: Array.isArray(expectedStatus) ? expectedStatus : [expectedStatus] };
|
|
11973
|
-
const updatedDoc = await collection.findOneAndUpdate(filter, [{ $set: {
|
|
12275
|
+
const updatedDoc = await withRunFence(this.#connector, check, (session) => collection.findOneAndUpdate(filter, [{ $set: {
|
|
11974
12276
|
snapshot: { $mergeObjects: ["$snapshot", state] },
|
|
11975
12277
|
updatedAt: /* @__PURE__ */ new Date()
|
|
11976
|
-
} }], {
|
|
12278
|
+
} }], {
|
|
12279
|
+
returnDocument: "after",
|
|
12280
|
+
session
|
|
12281
|
+
}));
|
|
11977
12282
|
if (!updatedDoc) return;
|
|
11978
12283
|
const snapshot = typeof updatedDoc.snapshot === "string" ? JSON.parse(updatedDoc.snapshot) : updatedDoc.snapshot;
|
|
11979
12284
|
if (!snapshot?.context) throw new _mastra_core_error.MastraError({
|
|
@@ -11988,7 +12293,7 @@ var WorkflowsStorageMongoDB = class WorkflowsStorageMongoDB extends _mastra_core
|
|
|
11988
12293
|
});
|
|
11989
12294
|
return snapshot;
|
|
11990
12295
|
} catch (error) {
|
|
11991
|
-
if (error instanceof _mastra_core_error.MastraError) throw error;
|
|
12296
|
+
if (error instanceof _mastra_core_error.MastraError || (0, _mastra_core_storage.isRunFenceConflictError)(error)) throw error;
|
|
11992
12297
|
throw new _mastra_core_error.MastraError({
|
|
11993
12298
|
id: (0, _mastra_core_storage.createStorageErrorId)("MONGODB", "UPDATE_WORKFLOW_STATE", "FAILED"),
|
|
11994
12299
|
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
@@ -12000,10 +12305,12 @@ var WorkflowsStorageMongoDB = class WorkflowsStorageMongoDB extends _mastra_core
|
|
|
12000
12305
|
}, error);
|
|
12001
12306
|
}
|
|
12002
12307
|
}
|
|
12003
|
-
async persistWorkflowSnapshot({ workflowName, runId, resourceId, snapshot, createdAt, updatedAt }) {
|
|
12308
|
+
async persistWorkflowSnapshot({ workflowName, runId, resourceId, snapshot, createdAt, updatedAt, fence }) {
|
|
12309
|
+
const check = this.#runFenceCheck(fence, runId, "persistWorkflowSnapshot");
|
|
12004
12310
|
try {
|
|
12005
12311
|
const now = /* @__PURE__ */ new Date();
|
|
12006
|
-
|
|
12312
|
+
const collection = await this.getCollection(_mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT);
|
|
12313
|
+
await withRunFence(this.#connector, check, (session) => collection.updateOne({
|
|
12007
12314
|
workflow_name: workflowName,
|
|
12008
12315
|
run_id: runId
|
|
12009
12316
|
}, {
|
|
@@ -12015,8 +12322,12 @@ var WorkflowsStorageMongoDB = class WorkflowsStorageMongoDB extends _mastra_core
|
|
|
12015
12322
|
updatedAt: updatedAt ?? now
|
|
12016
12323
|
},
|
|
12017
12324
|
$setOnInsert: { createdAt: createdAt ?? now }
|
|
12018
|
-
}, {
|
|
12325
|
+
}, {
|
|
12326
|
+
upsert: true,
|
|
12327
|
+
session
|
|
12328
|
+
}));
|
|
12019
12329
|
} catch (error) {
|
|
12330
|
+
if ((0, _mastra_core_storage.isRunFenceConflictError)(error)) throw error;
|
|
12020
12331
|
throw new _mastra_core_error.MastraError({
|
|
12021
12332
|
id: (0, _mastra_core_storage.createStorageErrorId)("MONGODB", "PERSIST_WORKFLOW_SNAPSHOT", "FAILED"),
|
|
12022
12333
|
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
@@ -12109,13 +12420,16 @@ var WorkflowsStorageMongoDB = class WorkflowsStorageMongoDB extends _mastra_core
|
|
|
12109
12420
|
}, error);
|
|
12110
12421
|
}
|
|
12111
12422
|
}
|
|
12112
|
-
async deleteWorkflowRunById({ runId, workflowName }) {
|
|
12423
|
+
async deleteWorkflowRunById({ runId, workflowName, fence }) {
|
|
12424
|
+
const check = this.#runFenceCheck(fence, runId, "deleteWorkflowRunById");
|
|
12113
12425
|
try {
|
|
12114
|
-
|
|
12426
|
+
const collection = await this.getCollection(_mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT);
|
|
12427
|
+
await withRunFence(this.#connector, check, (session) => collection.deleteOne({
|
|
12115
12428
|
workflow_name: workflowName,
|
|
12116
12429
|
run_id: runId
|
|
12117
|
-
});
|
|
12430
|
+
}, { session }));
|
|
12118
12431
|
} catch (error) {
|
|
12432
|
+
if ((0, _mastra_core_storage.isRunFenceConflictError)(error)) throw error;
|
|
12119
12433
|
throw new _mastra_core_error.MastraError({
|
|
12120
12434
|
id: (0, _mastra_core_storage.createStorageErrorId)("MONGODB", "DELETE_WORKFLOW_RUN_BY_ID", "FAILED"),
|
|
12121
12435
|
domain: _mastra_core_error.ErrorDomain.STORAGE,
|