@mastra/pg 1.31.0-alpha.3 → 1.31.0-alpha.4
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-retention.md +21 -18
- package/dist/index.cjs +394 -88
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +395 -89
- package/dist/index.js.map +1 -1
- package/dist/storage/db/index.d.ts +8 -5
- package/dist/storage/db/index.d.ts.map +1 -1
- package/dist/storage/db/run-fencing.d.ts +23 -0
- package/dist/storage/db/run-fencing.d.ts.map +1 -0
- package/dist/storage/domains/agents/index.d.ts.map +1 -1
- package/dist/storage/domains/mcp-clients/index.d.ts.map +1 -1
- package/dist/storage/domains/mcp-servers/index.d.ts.map +1 -1
- package/dist/storage/domains/memory/index.d.ts +21 -7
- package/dist/storage/domains/memory/index.d.ts.map +1 -1
- package/dist/storage/domains/prompt-blocks/index.d.ts.map +1 -1
- package/dist/storage/domains/scorer-definitions/index.d.ts.map +1 -1
- package/dist/storage/domains/skills/index.d.ts.map +1 -1
- package/dist/storage/domains/workflows/index.d.ts +21 -6
- package/dist/storage/domains/workflows/index.d.ts.map +1 -1
- package/dist/storage/domains/workspaces/index.d.ts.map +1 -1
- package/dist/storage/retention.d.ts +3 -3
- package/dist/storage/retention.d.ts.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ErrorCategory, ErrorDomain, MastraError } from "@mastra/core/error";
|
|
2
2
|
import * as coreStorage from "@mastra/core/storage";
|
|
3
|
-
import { AgentsStorage, BRANCH_SPAN_TYPES, BackgroundTasksStorage, BlobStore, ChannelsStorage, DATASETS_SCHEMA, DATASET_ITEMS_SCHEMA, DATASET_VERSIONS_SCHEMA, DatasetsStorage, EXPERIMENTS_SCHEMA, EXPERIMENT_RESULTS_SCHEMA, EntityType, ExperimentsStorage, FactoryStorage, FavoritesStorage, KNOWLEDGE_SEMANTIC_OUTBOX_SCHEMA, KnowledgeConflictError, KnowledgeNotFoundError, KnowledgeStorage, MCPClientsStorage, MCPServersStorage, METRIC_DISTINCT_COLUMNS, MastraCompositeStore, MemoryStorage, NotificationsStorage, OBSERVATIONAL_MEMORY_TABLE_SCHEMA, ObservabilityStorage, PromptBlocksStorage, SchedulesStorage, ScorerDefinitionsStorage, ScoresStorage, SkillsStorage, TABLE_AGENTS, TABLE_AGENT_VERSIONS, TABLE_BACKGROUND_TASKS, TABLE_CHANNEL_CONFIG, TABLE_CHANNEL_INSTALLATIONS, TABLE_CONFIGS, TABLE_DATASETS, TABLE_DATASET_ITEMS, TABLE_DATASET_VERSIONS, TABLE_EXPERIMENTS, TABLE_EXPERIMENT_RESULTS, TABLE_FAVORITES, TABLE_KNOWLEDGE_ACTIVITY, TABLE_KNOWLEDGE_MENTIONS, TABLE_KNOWLEDGE_NODES, TABLE_KNOWLEDGE_RECORDS, TABLE_KNOWLEDGE_SEMANTIC_OUTBOX, TABLE_MCP_CLIENTS, TABLE_MCP_CLIENT_VERSIONS, TABLE_MCP_SERVERS, TABLE_MCP_SERVER_VERSIONS, TABLE_MESSAGES, TABLE_NOTIFICATIONS, TABLE_PROMPT_BLOCKS, TABLE_PROMPT_BLOCK_VERSIONS, TABLE_RESOURCES, TABLE_SCHEDULES, TABLE_SCHEDULE_TRIGGERS, TABLE_SCHEMAS, TABLE_SCORERS, TABLE_SCORER_DEFINITIONS, TABLE_SCORER_DEFINITION_VERSIONS, TABLE_SKILLS, TABLE_SKILL_BLOBS, TABLE_SKILL_VERSIONS, TABLE_SPANS, TABLE_THREADS, TABLE_THREAD_STATE, TABLE_TOOL_PROVIDER_CONNECTIONS, TABLE_WORKFLOW_DEFINITIONS, TABLE_WORKFLOW_SNAPSHOT, TABLE_WORKSPACES, TABLE_WORKSPACE_VERSIONS, ThreadStateStorage, ToolProviderConnectionsStorage, TraceStatus, UniqueViolationError, WorkflowDefinitionsStorage, WorkflowsStorage, WorkspacesStorage, calculatePagination, canonicalizeKnowledgeScope, createKnowledgeUlid, createStorageErrorId, createVectorErrorId, ensureDate, executeRetentionPrune, getDefaultValue, getSqlType, hasErrorCode, isKnowledgeScopeVisible, knowledgeScopeKey, knowledgeSemanticDocumentId, knowledgeSemanticIdempotencyKey, listBranchesArgsSchema, listFeedbackArgsSchema, listLogsArgsSchema, listMetricsArgsSchema, listScoresArgsSchema, listTracesArgsSchema, matchesExpectedWorkflowStatus, mergeWorkflowStepResult, normalizePerPage, normalizeScheduleTarget, parseDuration, parseKnowledgeNodeCursor, parseKnowledgeWikilinks, resolveListOrderBy, resolveRetentionTargets, retentionCutoffMs, runRetentionBatches, safelyParseJSON, storageMessageMatchesMetadataFilter, toTraceSpans, transformScoreRow, validateStorageMetadataFilter } from "@mastra/core/storage";
|
|
3
|
+
import { AgentsStorage, BRANCH_SPAN_TYPES, BackgroundTasksStorage, BlobStore, ChannelsStorage, DATASETS_SCHEMA, DATASET_ITEMS_SCHEMA, DATASET_VERSIONS_SCHEMA, DatasetsStorage, EXPERIMENTS_SCHEMA, EXPERIMENT_RESULTS_SCHEMA, EntityType, ExperimentsStorage, FactoryStorage, FavoritesStorage, KNOWLEDGE_SEMANTIC_OUTBOX_SCHEMA, KnowledgeConflictError, KnowledgeNotFoundError, KnowledgeStorage, MCPClientsStorage, MCPServersStorage, METRIC_DISTINCT_COLUMNS, MastraCompositeStore, MemoryStorage, NotificationsStorage, OBSERVATIONAL_MEMORY_TABLE_SCHEMA, ObservabilityStorage, PromptBlocksStorage, RUN_FENCING_TABLE_SCHEMAS, RunFenceConflictError, SchedulesStorage, ScorerDefinitionsStorage, ScoresStorage, SkillsStorage, TABLE_AGENTS, TABLE_AGENT_VERSIONS, TABLE_BACKGROUND_TASKS, TABLE_CHANNEL_CONFIG, TABLE_CHANNEL_INSTALLATIONS, TABLE_CONFIGS, TABLE_DATASETS, TABLE_DATASET_ITEMS, TABLE_DATASET_VERSIONS, TABLE_EXPERIMENTS, TABLE_EXPERIMENT_RESULTS, TABLE_FAVORITES, TABLE_KNOWLEDGE_ACTIVITY, TABLE_KNOWLEDGE_MENTIONS, TABLE_KNOWLEDGE_NODES, TABLE_KNOWLEDGE_RECORDS, TABLE_KNOWLEDGE_SEMANTIC_OUTBOX, TABLE_MCP_CLIENTS, TABLE_MCP_CLIENT_VERSIONS, TABLE_MCP_SERVERS, TABLE_MCP_SERVER_VERSIONS, TABLE_MEMORY_RUN_FENCES, TABLE_MESSAGES, TABLE_NOTIFICATIONS, TABLE_PROMPT_BLOCKS, TABLE_PROMPT_BLOCK_VERSIONS, TABLE_RESOURCES, TABLE_SCHEDULES, TABLE_SCHEDULE_TRIGGERS, TABLE_SCHEMAS, TABLE_SCORERS, TABLE_SCORER_DEFINITIONS, TABLE_SCORER_DEFINITION_VERSIONS, TABLE_SKILLS, TABLE_SKILL_BLOBS, TABLE_SKILL_VERSIONS, TABLE_SPANS, TABLE_THREADS, TABLE_THREAD_STATE, TABLE_TOOL_PROVIDER_CONNECTIONS, TABLE_WORKFLOW_DEFINITIONS, TABLE_WORKFLOW_RUN_OWNERS, TABLE_WORKFLOW_SNAPSHOT, TABLE_WORKSPACES, TABLE_WORKSPACE_VERSIONS, ThreadStateStorage, ToolProviderConnectionsStorage, TraceStatus, UniqueViolationError, WorkflowDefinitionsStorage, WorkflowsStorage, WorkspacesStorage, calculatePagination, canonicalizeKnowledgeScope, createKnowledgeUlid, createStorageErrorId, createVectorErrorId, ensureDate, executeRetentionPrune, getDefaultValue, getSqlType, hasErrorCode, isKnowledgeScopeVisible, isRunFenceConflictError, knowledgeScopeKey, knowledgeSemanticDocumentId, knowledgeSemanticIdempotencyKey, listBranchesArgsSchema, listFeedbackArgsSchema, listLogsArgsSchema, listMetricsArgsSchema, listScoresArgsSchema, listTracesArgsSchema, matchesExpectedWorkflowStatus, matchesRunFence, mergeWorkflowStepResult, normalizePerPage, normalizeScheduleTarget, parseDuration, parseKnowledgeNodeCursor, parseKnowledgeWikilinks, resolveListOrderBy, resolveRetentionTargets, resolveRunFence, retentionCutoffMs, runRetentionBatches, safelyParseJSON, storageMessageMatchesMetadataFilter, toTraceSpans, transformScoreRow, validateStorageMetadataFilter } from "@mastra/core/storage";
|
|
4
4
|
import { parseFieldKey, parseSqlIdentifier } from "@mastra/core/utils";
|
|
5
5
|
import { MastraVector, validateTopK, validateUpsertInput } from "@mastra/core/vector";
|
|
6
6
|
import { Mutex } from "async-mutex";
|
|
@@ -3189,9 +3189,10 @@ var PgDB = class extends MastraBase {
|
|
|
3189
3189
|
}
|
|
3190
3190
|
await flush();
|
|
3191
3191
|
}
|
|
3192
|
-
|
|
3192
|
+
/** `client` lets a caller run the insert inside its own transaction. */
|
|
3193
|
+
async insert({ tableName, record }, client = this.client) {
|
|
3193
3194
|
try {
|
|
3194
|
-
await this.executeInsert(
|
|
3195
|
+
await this.executeInsert(client, {
|
|
3195
3196
|
tableName,
|
|
3196
3197
|
record
|
|
3197
3198
|
});
|
|
@@ -4025,13 +4026,15 @@ MIGRATION REQUIRED: Duplicate spans detected in ${duplicateInfo.tableName}\n====
|
|
|
4025
4026
|
indexName: tableName,
|
|
4026
4027
|
schemaName: getSchemaName$6(this.schemaName)
|
|
4027
4028
|
});
|
|
4029
|
+
const parsedColumn = `"${parseSqlIdentifier(column, "column name")}"`;
|
|
4028
4030
|
const sql = `
|
|
4029
4031
|
DELETE FROM ${fullTableName}
|
|
4030
4032
|
WHERE ctid IN (
|
|
4031
4033
|
SELECT ctid FROM ${fullTableName}
|
|
4032
|
-
WHERE ${
|
|
4034
|
+
WHERE ${parsedColumn} < $1
|
|
4033
4035
|
LIMIT $2
|
|
4034
4036
|
)
|
|
4037
|
+
AND ${parsedColumn} < $1
|
|
4035
4038
|
`;
|
|
4036
4039
|
return (await this.client.query(sql, [cutoff, limit])).rowCount ?? 0;
|
|
4037
4040
|
}
|
|
@@ -4494,6 +4497,7 @@ var AgentsPG = class AgentsPG extends AgentsStorage {
|
|
|
4494
4497
|
}
|
|
4495
4498
|
async create(input) {
|
|
4496
4499
|
const { agent } = input;
|
|
4500
|
+
let draftInserted = false;
|
|
4497
4501
|
try {
|
|
4498
4502
|
const agentsTable = getTableName$5({
|
|
4499
4503
|
indexName: TABLE_AGENTS,
|
|
@@ -4520,6 +4524,7 @@ var AgentsPG = class AgentsPG extends AgentsStorage {
|
|
|
4520
4524
|
nowIso,
|
|
4521
4525
|
nowIso
|
|
4522
4526
|
]);
|
|
4527
|
+
draftInserted = true;
|
|
4523
4528
|
const { id: _id, authorId: _authorId, visibility: _visibility, metadata: _metadata, ...snapshotConfig } = agent;
|
|
4524
4529
|
const versionId = crypto.randomUUID();
|
|
4525
4530
|
await this.createVersion({
|
|
@@ -4542,14 +4547,14 @@ var AgentsPG = class AgentsPG extends AgentsStorage {
|
|
|
4542
4547
|
updatedAt: now
|
|
4543
4548
|
};
|
|
4544
4549
|
} catch (error) {
|
|
4545
|
-
if (
|
|
4546
|
-
try {
|
|
4550
|
+
if (draftInserted) try {
|
|
4547
4551
|
const agentsTable = getTableName$5({
|
|
4548
4552
|
indexName: TABLE_AGENTS,
|
|
4549
4553
|
schemaName: getSchemaName$5(this.#schema)
|
|
4550
4554
|
});
|
|
4551
4555
|
await this.#db.client.none(`DELETE FROM ${agentsTable} WHERE id = $1 AND status = 'draft' AND "activeVersionId" IS NULL`, [agent.id]);
|
|
4552
4556
|
} catch {}
|
|
4557
|
+
if (error instanceof MastraError) throw error;
|
|
4553
4558
|
throw new MastraError({
|
|
4554
4559
|
id: createStorageErrorId("PG", "CREATE_AGENT", "FAILED"),
|
|
4555
4560
|
domain: ErrorDomain.STORAGE,
|
|
@@ -10545,6 +10550,7 @@ var MCPClientsPG = class MCPClientsPG extends MCPClientsStorage {
|
|
|
10545
10550
|
}
|
|
10546
10551
|
async create(input) {
|
|
10547
10552
|
const { mcpClient } = input;
|
|
10553
|
+
let draftInserted = false;
|
|
10548
10554
|
try {
|
|
10549
10555
|
const tableName = getTableName$5({
|
|
10550
10556
|
indexName: TABLE_MCP_CLIENTS,
|
|
@@ -10567,6 +10573,7 @@ var MCPClientsPG = class MCPClientsPG extends MCPClientsStorage {
|
|
|
10567
10573
|
nowIso,
|
|
10568
10574
|
nowIso
|
|
10569
10575
|
]);
|
|
10576
|
+
draftInserted = true;
|
|
10570
10577
|
const { id: _id, authorId: _authorId, metadata: _metadata, ...snapshotConfig } = mcpClient;
|
|
10571
10578
|
const versionId = crypto.randomUUID();
|
|
10572
10579
|
await this.createVersion({
|
|
@@ -10587,7 +10594,7 @@ var MCPClientsPG = class MCPClientsPG extends MCPClientsStorage {
|
|
|
10587
10594
|
updatedAt: now
|
|
10588
10595
|
};
|
|
10589
10596
|
} catch (error) {
|
|
10590
|
-
try {
|
|
10597
|
+
if (draftInserted) try {
|
|
10591
10598
|
const tableName = getTableName$5({
|
|
10592
10599
|
indexName: TABLE_MCP_CLIENTS,
|
|
10593
10600
|
schemaName: getSchemaName$5(this.#schema)
|
|
@@ -11113,6 +11120,7 @@ var MCPServersPG = class MCPServersPG extends MCPServersStorage {
|
|
|
11113
11120
|
}
|
|
11114
11121
|
async create(input) {
|
|
11115
11122
|
const { mcpServer } = input;
|
|
11123
|
+
let draftInserted = false;
|
|
11116
11124
|
try {
|
|
11117
11125
|
const tableName = getTableName$5({
|
|
11118
11126
|
indexName: TABLE_MCP_SERVERS,
|
|
@@ -11134,6 +11142,7 @@ var MCPServersPG = class MCPServersPG extends MCPServersStorage {
|
|
|
11134
11142
|
nowIso,
|
|
11135
11143
|
nowIso
|
|
11136
11144
|
]);
|
|
11145
|
+
draftInserted = true;
|
|
11137
11146
|
const { id: _id, authorId: _authorId, metadata: _metadata, ...snapshotConfig } = mcpServer;
|
|
11138
11147
|
const versionId = crypto.randomUUID();
|
|
11139
11148
|
await this.createVersion({
|
|
@@ -11154,7 +11163,7 @@ var MCPServersPG = class MCPServersPG extends MCPServersStorage {
|
|
|
11154
11163
|
updatedAt: now
|
|
11155
11164
|
};
|
|
11156
11165
|
} catch (error) {
|
|
11157
|
-
try {
|
|
11166
|
+
if (draftInserted) try {
|
|
11158
11167
|
const tableName = getTableName$5({
|
|
11159
11168
|
indexName: TABLE_MCP_SERVERS,
|
|
11160
11169
|
schemaName: getSchemaName$5(this.#schema)
|
|
@@ -11578,6 +11587,38 @@ var MCPServersPG = class MCPServersPG extends MCPServersStorage {
|
|
|
11578
11587
|
}
|
|
11579
11588
|
};
|
|
11580
11589
|
//#endregion
|
|
11590
|
+
//#region src/storage/db/run-fencing.ts
|
|
11591
|
+
/**
|
|
11592
|
+
* Epoch milliseconds on the database clock. `clock_timestamp()` rather than
|
|
11593
|
+
* `now()`: a statement can wait on a row lock, and lease math must use the
|
|
11594
|
+
* time it actually runs, not when its transaction started.
|
|
11595
|
+
*/
|
|
11596
|
+
const DB_NOW_MS = `(EXTRACT(EPOCH FROM clock_timestamp()) * 1000)::bigint`;
|
|
11597
|
+
/**
|
|
11598
|
+
* The check half of a fenced write; call it first inside the write's
|
|
11599
|
+
* transaction. `FOR SHARE` holds the claim row until commit, so a claim that
|
|
11600
|
+
* updates the row waits for the write to finish, and every later write sees
|
|
11601
|
+
* the new claim.
|
|
11602
|
+
*/
|
|
11603
|
+
async function assertRunFence(t, claimsTable, fence, operation) {
|
|
11604
|
+
const row = await t.oneOrNone(`SELECT generation, "ownerId" FROM ${claimsTable} WHERE "runId" = $1 FOR SHARE`, [fence.runId]);
|
|
11605
|
+
if (!matchesRunFence(row && {
|
|
11606
|
+
generation: Number(row.generation),
|
|
11607
|
+
ownerId: row.ownerId
|
|
11608
|
+
}, fence)) throw new RunFenceConflictError(fence, operation);
|
|
11609
|
+
}
|
|
11610
|
+
/**
|
|
11611
|
+
* Runs `write` directly when it carries no fence, or in a transaction behind
|
|
11612
|
+
* the fence check when it does.
|
|
11613
|
+
*/
|
|
11614
|
+
function withRunFence(client, claimsTable, fence, operation, write) {
|
|
11615
|
+
if (!fence) return write(client);
|
|
11616
|
+
return client.tx(async (t) => {
|
|
11617
|
+
await assertRunFence(t, claimsTable, fence, operation);
|
|
11618
|
+
return write(t);
|
|
11619
|
+
});
|
|
11620
|
+
}
|
|
11621
|
+
//#endregion
|
|
11581
11622
|
//#region src/storage/domains/memory/index.ts
|
|
11582
11623
|
/**
|
|
11583
11624
|
* Local constant for the observational memory table name.
|
|
@@ -11678,6 +11719,10 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
11678
11719
|
* and are indexed for fast batched deletes. Cascade order is enforced in
|
|
11679
11720
|
* `prune()` (children before threads), not here. Observational memory has no
|
|
11680
11721
|
* timestamp anchor and is deliberately excluded.
|
|
11722
|
+
*
|
|
11723
|
+
* Run fences anchor on `retiredAt` (epoch ms), which stays NULL until the
|
|
11724
|
+
* execution holding the fence settles, so a running execution's fence is
|
|
11725
|
+
* never pruned.
|
|
11681
11726
|
*/
|
|
11682
11727
|
static retentionTables = {
|
|
11683
11728
|
messages: {
|
|
@@ -11694,6 +11739,12 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
11694
11739
|
table: TABLE_THREADS,
|
|
11695
11740
|
column: "createdAtZ",
|
|
11696
11741
|
indexed: true
|
|
11742
|
+
},
|
|
11743
|
+
runFences: {
|
|
11744
|
+
table: TABLE_MEMORY_RUN_FENCES,
|
|
11745
|
+
column: "retiredAt",
|
|
11746
|
+
indexed: true,
|
|
11747
|
+
anchorType: "epoch-ms"
|
|
11697
11748
|
}
|
|
11698
11749
|
};
|
|
11699
11750
|
#db;
|
|
@@ -11757,6 +11808,10 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
11757
11808
|
});
|
|
11758
11809
|
await this.#db.createIndexFromStatement("idx_om_lookup_key", `CREATE INDEX IF NOT EXISTS idx_om_lookup_key ON ${omTableName} ("lookupKey")`);
|
|
11759
11810
|
}
|
|
11811
|
+
await this.#db.createTable({
|
|
11812
|
+
tableName: TABLE_MEMORY_RUN_FENCES,
|
|
11813
|
+
schema: RUN_FENCING_TABLE_SCHEMAS[TABLE_MEMORY_RUN_FENCES]
|
|
11814
|
+
});
|
|
11760
11815
|
await this.createDefaultIndexes();
|
|
11761
11816
|
await this.createCustomIndexes();
|
|
11762
11817
|
}
|
|
@@ -11834,6 +11889,12 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
11834
11889
|
statements.push(`CREATE INDEX IF NOT EXISTS "${idxPrefix}idx_om_lookup_key" ON ${fullOmTableName} ("lookupKey");`);
|
|
11835
11890
|
}
|
|
11836
11891
|
for (const idx of MemoryPG.getDefaultIndexDefs(schemaPrefix)) statements.push(generateIndexSQL(idx, schemaName));
|
|
11892
|
+
statements.push(generateTableSQL({
|
|
11893
|
+
tableName: TABLE_MEMORY_RUN_FENCES,
|
|
11894
|
+
schema: RUN_FENCING_TABLE_SCHEMAS[TABLE_MEMORY_RUN_FENCES],
|
|
11895
|
+
schemaName,
|
|
11896
|
+
includeAllConstraints: true
|
|
11897
|
+
}));
|
|
11837
11898
|
return statements;
|
|
11838
11899
|
}
|
|
11839
11900
|
/**
|
|
@@ -11869,6 +11930,61 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
11869
11930
|
await this.#db.clearTable({ tableName: TABLE_MESSAGES });
|
|
11870
11931
|
await this.#db.clearTable({ tableName: TABLE_THREADS });
|
|
11871
11932
|
await this.#db.clearTable({ tableName: TABLE_RESOURCES });
|
|
11933
|
+
await this.#db.clearTable({ tableName: TABLE_MEMORY_RUN_FENCES });
|
|
11934
|
+
}
|
|
11935
|
+
supportsRunFencing() {
|
|
11936
|
+
return true;
|
|
11937
|
+
}
|
|
11938
|
+
#runFencesTable() {
|
|
11939
|
+
return getTableName$3({
|
|
11940
|
+
indexName: TABLE_MEMORY_RUN_FENCES,
|
|
11941
|
+
schemaName: getSchemaName$3(this.#schema)
|
|
11942
|
+
});
|
|
11943
|
+
}
|
|
11944
|
+
/** Runs `write` behind the run's fence check when it carries a fence. */
|
|
11945
|
+
#fenced(fence, operation, write) {
|
|
11946
|
+
return withRunFence(this.#db.client, this.#runFencesTable(), resolveRunFence(this, fence), operation, write);
|
|
11947
|
+
}
|
|
11948
|
+
async raiseRunFence(fence) {
|
|
11949
|
+
try {
|
|
11950
|
+
return await this.#db.client.oneOrNone(`INSERT INTO ${this.#runFencesTable()} AS f ("runId", generation, "ownerId")
|
|
11951
|
+
VALUES ($1, $2, $3)
|
|
11952
|
+
ON CONFLICT ("runId") DO UPDATE
|
|
11953
|
+
SET generation = EXCLUDED.generation, "ownerId" = EXCLUDED."ownerId", "retiredAt" = NULL
|
|
11954
|
+
WHERE f.generation < EXCLUDED.generation
|
|
11955
|
+
OR (f.generation = EXCLUDED.generation AND f."ownerId" = EXCLUDED."ownerId")
|
|
11956
|
+
RETURNING "runId"`, [
|
|
11957
|
+
fence.runId,
|
|
11958
|
+
fence.generation,
|
|
11959
|
+
fence.ownerId
|
|
11960
|
+
]) !== null;
|
|
11961
|
+
} catch (error) {
|
|
11962
|
+
throw new MastraError({
|
|
11963
|
+
id: createStorageErrorId("PG", "RAISE_RUN_FENCE", "FAILED"),
|
|
11964
|
+
domain: ErrorDomain.STORAGE,
|
|
11965
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
11966
|
+
details: { runId: fence.runId }
|
|
11967
|
+
}, error);
|
|
11968
|
+
}
|
|
11969
|
+
}
|
|
11970
|
+
async retireRunFence(fence) {
|
|
11971
|
+
try {
|
|
11972
|
+
return await this.#db.client.oneOrNone(`UPDATE ${this.#runFencesTable()}
|
|
11973
|
+
SET "retiredAt" = ${DB_NOW_MS}
|
|
11974
|
+
WHERE "runId" = $1 AND generation = $2 AND "ownerId" = $3
|
|
11975
|
+
RETURNING "runId"`, [
|
|
11976
|
+
fence.runId,
|
|
11977
|
+
fence.generation,
|
|
11978
|
+
fence.ownerId
|
|
11979
|
+
]) !== null;
|
|
11980
|
+
} catch (error) {
|
|
11981
|
+
throw new MastraError({
|
|
11982
|
+
id: createStorageErrorId("PG", "RETIRE_RUN_FENCE", "FAILED"),
|
|
11983
|
+
domain: ErrorDomain.STORAGE,
|
|
11984
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
11985
|
+
details: { runId: fence.runId }
|
|
11986
|
+
}, error);
|
|
11987
|
+
}
|
|
11872
11988
|
}
|
|
11873
11989
|
/**
|
|
11874
11990
|
* Deletes rows older than the configured `maxAge` per table, in bounded,
|
|
@@ -11889,7 +12005,8 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
11889
12005
|
order: [
|
|
11890
12006
|
"messages",
|
|
11891
12007
|
"resources",
|
|
11892
|
-
"threads"
|
|
12008
|
+
"threads",
|
|
12009
|
+
"runFences"
|
|
11893
12010
|
]
|
|
11894
12011
|
});
|
|
11895
12012
|
const results = await runPrune({
|
|
@@ -12147,7 +12264,7 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
12147
12264
|
throw mastraError;
|
|
12148
12265
|
}
|
|
12149
12266
|
}
|
|
12150
|
-
async saveThread({ thread }) {
|
|
12267
|
+
async saveThread({ thread, fence }) {
|
|
12151
12268
|
try {
|
|
12152
12269
|
const tableName = getTableName$3({
|
|
12153
12270
|
indexName: TABLE_THREADS,
|
|
@@ -12156,7 +12273,7 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
12156
12273
|
const createdAt = toUtcISOString(thread.createdAt);
|
|
12157
12274
|
const updatedAt = toUtcISOString(thread.updatedAt);
|
|
12158
12275
|
const metadataJson = thread.metadata ? toPgJson(thread.metadata) : null;
|
|
12159
|
-
await this.#
|
|
12276
|
+
await this.#fenced(fence, "saveThread", (q) => q.none(`INSERT INTO ${tableName} (
|
|
12160
12277
|
id,
|
|
12161
12278
|
"resourceId",
|
|
12162
12279
|
title,
|
|
@@ -12182,12 +12299,13 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
12182
12299
|
createdAt,
|
|
12183
12300
|
updatedAt,
|
|
12184
12301
|
updatedAt
|
|
12185
|
-
]);
|
|
12302
|
+
]));
|
|
12186
12303
|
return {
|
|
12187
12304
|
...thread,
|
|
12188
12305
|
metadata: metadataJson ? JSON.parse(metadataJson) : thread.metadata
|
|
12189
12306
|
};
|
|
12190
12307
|
} catch (error) {
|
|
12308
|
+
if (isRunFenceConflictError(error)) throw error;
|
|
12191
12309
|
throw new MastraError({
|
|
12192
12310
|
id: createStorageErrorId("PG", "SAVE_THREAD", "FAILED"),
|
|
12193
12311
|
domain: ErrorDomain.STORAGE,
|
|
@@ -12196,29 +12314,30 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
12196
12314
|
}, error);
|
|
12197
12315
|
}
|
|
12198
12316
|
}
|
|
12199
|
-
async updateThread({ id, title, metadata }) {
|
|
12317
|
+
async updateThread({ id, title, metadata, fence }) {
|
|
12200
12318
|
const threadTableName = getTableName$3({
|
|
12201
12319
|
indexName: TABLE_THREADS,
|
|
12202
12320
|
schemaName: getSchemaName$3(this.#schema)
|
|
12203
12321
|
});
|
|
12204
|
-
const existingThread = await this.#getThreadById(this.#db.client, { threadId: id });
|
|
12205
|
-
if (!existingThread) throw new MastraError({
|
|
12206
|
-
id: createStorageErrorId("PG", "UPDATE_THREAD", "FAILED"),
|
|
12207
|
-
domain: ErrorDomain.STORAGE,
|
|
12208
|
-
category: ErrorCategory.USER,
|
|
12209
|
-
text: `Thread ${id} not found`,
|
|
12210
|
-
details: {
|
|
12211
|
-
threadId: id,
|
|
12212
|
-
title: title ?? null
|
|
12213
|
-
}
|
|
12214
|
-
});
|
|
12215
|
-
const mergedMetadata = {
|
|
12216
|
-
...existingThread.metadata,
|
|
12217
|
-
...metadata
|
|
12218
|
-
};
|
|
12219
12322
|
try {
|
|
12220
|
-
|
|
12221
|
-
|
|
12323
|
+
return await this.#fenced(fence, "updateThread", async (q) => {
|
|
12324
|
+
const existingThread = await this.#getThreadById(q, { threadId: id });
|
|
12325
|
+
if (!existingThread) throw new MastraError({
|
|
12326
|
+
id: createStorageErrorId("PG", "UPDATE_THREAD", "FAILED"),
|
|
12327
|
+
domain: ErrorDomain.STORAGE,
|
|
12328
|
+
category: ErrorCategory.USER,
|
|
12329
|
+
text: `Thread ${id} not found`,
|
|
12330
|
+
details: {
|
|
12331
|
+
threadId: id,
|
|
12332
|
+
title: title ?? null
|
|
12333
|
+
}
|
|
12334
|
+
});
|
|
12335
|
+
const mergedMetadata = {
|
|
12336
|
+
...existingThread.metadata,
|
|
12337
|
+
...metadata
|
|
12338
|
+
};
|
|
12339
|
+
const nowStr = toUtcISOString(/* @__PURE__ */ new Date());
|
|
12340
|
+
const thread = await q.one(`UPDATE ${threadTableName}
|
|
12222
12341
|
SET
|
|
12223
12342
|
title = COALESCE($1, title),
|
|
12224
12343
|
metadata = $2,
|
|
@@ -12227,21 +12346,23 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
12227
12346
|
WHERE id = $5
|
|
12228
12347
|
RETURNING *
|
|
12229
12348
|
`, [
|
|
12230
|
-
|
|
12231
|
-
|
|
12232
|
-
|
|
12233
|
-
|
|
12234
|
-
|
|
12235
|
-
|
|
12236
|
-
|
|
12237
|
-
|
|
12238
|
-
|
|
12239
|
-
|
|
12240
|
-
|
|
12241
|
-
|
|
12242
|
-
|
|
12243
|
-
|
|
12349
|
+
title ?? null,
|
|
12350
|
+
mergedMetadata,
|
|
12351
|
+
nowStr,
|
|
12352
|
+
nowStr,
|
|
12353
|
+
id
|
|
12354
|
+
]);
|
|
12355
|
+
return {
|
|
12356
|
+
id: thread.id,
|
|
12357
|
+
resourceId: thread.resourceId,
|
|
12358
|
+
title: thread.title,
|
|
12359
|
+
metadata: typeof thread.metadata === "string" ? JSON.parse(thread.metadata) : thread.metadata,
|
|
12360
|
+
createdAt: thread.createdAtZ || thread.createdAt,
|
|
12361
|
+
updatedAt: thread.updatedAtZ || thread.updatedAt
|
|
12362
|
+
};
|
|
12363
|
+
});
|
|
12244
12364
|
} catch (error) {
|
|
12365
|
+
if (error instanceof MastraError || isRunFenceConflictError(error)) throw error;
|
|
12245
12366
|
throw new MastraError({
|
|
12246
12367
|
id: createStorageErrorId("PG", "UPDATE_THREAD", "FAILED"),
|
|
12247
12368
|
domain: ErrorDomain.STORAGE,
|
|
@@ -12794,8 +12915,9 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
12794
12915
|
throw mastraError;
|
|
12795
12916
|
}
|
|
12796
12917
|
}
|
|
12797
|
-
async saveMessages({ messages }) {
|
|
12918
|
+
async saveMessages({ messages, fence: explicitFence }) {
|
|
12798
12919
|
if (messages.length === 0) return { messages: [] };
|
|
12920
|
+
const fence = resolveRunFence(this, explicitFence);
|
|
12799
12921
|
const threadId = messages[0]?.threadId;
|
|
12800
12922
|
if (!threadId) throw new MastraError({
|
|
12801
12923
|
id: createStorageErrorId("PG", "SAVE_MESSAGES", "FAILED"),
|
|
@@ -12823,6 +12945,7 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
12823
12945
|
});
|
|
12824
12946
|
const messagesToSave = dedupeMessagesForSave(messages);
|
|
12825
12947
|
await this.#db.client.tx(async (t) => {
|
|
12948
|
+
if (fence) await assertRunFence(t, this.#runFencesTable(), fence, "saveMessages");
|
|
12826
12949
|
for (let offset = 0; offset < messagesToSave.length; offset += MAX_MESSAGES_PER_INSERT) {
|
|
12827
12950
|
const batch = messagesToSave.slice(offset, offset + MAX_MESSAGES_PER_INSERT);
|
|
12828
12951
|
const values = [];
|
|
@@ -12869,7 +12992,7 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
12869
12992
|
});
|
|
12870
12993
|
return { messages: new MessageList().add(messagesWithParsedContent, "memory").get.all.db() };
|
|
12871
12994
|
} catch (error) {
|
|
12872
|
-
if (error instanceof MastraError) throw error;
|
|
12995
|
+
if (error instanceof MastraError || isRunFenceConflictError(error)) throw error;
|
|
12873
12996
|
throw new MastraError({
|
|
12874
12997
|
id: createStorageErrorId("PG", "SAVE_MESSAGES", "FAILED"),
|
|
12875
12998
|
domain: ErrorDomain.STORAGE,
|
|
@@ -12878,8 +13001,9 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
12878
13001
|
}, error);
|
|
12879
13002
|
}
|
|
12880
13003
|
}
|
|
12881
|
-
async updateMessages({ messages }) {
|
|
13004
|
+
async updateMessages({ messages, fence: explicitFence }) {
|
|
12882
13005
|
if (messages.length === 0) return [];
|
|
13006
|
+
const fence = resolveRunFence(this, explicitFence);
|
|
12883
13007
|
const messageIds = messages.map((m) => m.id);
|
|
12884
13008
|
const selectQuery = `SELECT id, content, role, type, "createdAt", "createdAtZ", thread_id AS "threadId", "resourceId" FROM ${getTableName$3({
|
|
12885
13009
|
indexName: TABLE_MESSAGES,
|
|
@@ -12895,6 +13019,7 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
12895
13019
|
});
|
|
12896
13020
|
const threadIdsToUpdate = /* @__PURE__ */ new Set();
|
|
12897
13021
|
await this.#db.client.tx(async (t) => {
|
|
13022
|
+
if (fence) await assertRunFence(t, this.#runFencesTable(), fence, "updateMessages");
|
|
12898
13023
|
const queries = [];
|
|
12899
13024
|
const columnMapping = { threadId: "thread_id" };
|
|
12900
13025
|
for (const existingMessage of existingMessages) {
|
|
@@ -12955,8 +13080,9 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
12955
13080
|
return message;
|
|
12956
13081
|
});
|
|
12957
13082
|
}
|
|
12958
|
-
async deleteMessages(messageIds) {
|
|
13083
|
+
async deleteMessages(messageIds, options) {
|
|
12959
13084
|
if (!messageIds || messageIds.length === 0) return;
|
|
13085
|
+
const fence = resolveRunFence(this, options?.fence);
|
|
12960
13086
|
try {
|
|
12961
13087
|
const messageTableName = getTableName$3({
|
|
12962
13088
|
indexName: TABLE_MESSAGES,
|
|
@@ -12967,12 +13093,14 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
12967
13093
|
schemaName: getSchemaName$3(this.#schema)
|
|
12968
13094
|
});
|
|
12969
13095
|
await this.#db.client.tx(async (t) => {
|
|
13096
|
+
if (fence) await assertRunFence(t, this.#runFencesTable(), fence, "deleteMessages");
|
|
12970
13097
|
const placeholders = messageIds.map((_, idx) => `$${idx + 1}`).join(",");
|
|
12971
13098
|
const threadIds = (await t.manyOrNone(`SELECT DISTINCT thread_id FROM ${messageTableName} WHERE id IN (${placeholders})`, messageIds))?.map((msg) => msg.thread_id).filter(Boolean) || [];
|
|
12972
13099
|
await t.none(`DELETE FROM ${messageTableName} WHERE id IN (${placeholders})`, messageIds);
|
|
12973
13100
|
if (threadIds.length > 0) await t.none(`UPDATE ${threadTableName} SET "updatedAt" = NOW(), "updatedAtZ" = NOW() WHERE id IN (${inPlaceholders(threadIds.length)})`, threadIds);
|
|
12974
13101
|
});
|
|
12975
13102
|
} catch (error) {
|
|
13103
|
+
if (isRunFenceConflictError(error)) throw error;
|
|
12976
13104
|
throw new MastraError({
|
|
12977
13105
|
id: createStorageErrorId("PG", "DELETE_MESSAGES", "FAILED"),
|
|
12978
13106
|
domain: ErrorDomain.STORAGE,
|
|
@@ -13000,6 +13128,9 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
13000
13128
|
};
|
|
13001
13129
|
}
|
|
13002
13130
|
async saveResource({ resource }) {
|
|
13131
|
+
return this.#insertResource(this.#db.client, resource);
|
|
13132
|
+
}
|
|
13133
|
+
async #insertResource(q, resource) {
|
|
13003
13134
|
const createdAt = toUtcISOString(resource.createdAt);
|
|
13004
13135
|
const updatedAt = toUtcISOString(resource.updatedAt);
|
|
13005
13136
|
const metadataJson = toPgJson(resource.metadata);
|
|
@@ -13011,7 +13142,7 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
13011
13142
|
createdAt,
|
|
13012
13143
|
updatedAt
|
|
13013
13144
|
}
|
|
13014
|
-
});
|
|
13145
|
+
}, q);
|
|
13015
13146
|
return {
|
|
13016
13147
|
...resource,
|
|
13017
13148
|
metadata: metadataJson ? JSON.parse(metadataJson) : resource.metadata
|
|
@@ -13022,9 +13153,11 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
13022
13153
|
indexName: TABLE_RESOURCES,
|
|
13023
13154
|
schemaName: getSchemaName$3(this.#schema)
|
|
13024
13155
|
});
|
|
13156
|
+
const fence = resolveRunFence(this, void 0);
|
|
13025
13157
|
const callbackError = {};
|
|
13026
13158
|
try {
|
|
13027
13159
|
return await this.#db.client.tx(async (t) => {
|
|
13160
|
+
if (fence) await assertRunFence(t, this.#runFencesTable(), fence, "mergeResourceWorkingMemory");
|
|
13028
13161
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
13029
13162
|
await t.none(`INSERT INTO ${tableName} (id, metadata, "createdAt", "createdAtZ", "updatedAt", "updatedAtZ")
|
|
13030
13163
|
VALUES ($1, $2, $3, $4, $5, $6) ON CONFLICT (id) DO NOTHING`, [
|
|
@@ -13068,8 +13201,15 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
13068
13201
|
}, error);
|
|
13069
13202
|
}
|
|
13070
13203
|
}
|
|
13071
|
-
async updateResource({ resourceId, workingMemory, metadata }) {
|
|
13072
|
-
|
|
13204
|
+
async updateResource({ resourceId, workingMemory, metadata, fence }) {
|
|
13205
|
+
return this.#fenced(fence, "updateResource", (q) => this.#updateResource(q, {
|
|
13206
|
+
resourceId,
|
|
13207
|
+
workingMemory,
|
|
13208
|
+
metadata
|
|
13209
|
+
}));
|
|
13210
|
+
}
|
|
13211
|
+
async #updateResource(q, { resourceId, workingMemory, metadata }) {
|
|
13212
|
+
const existingResource = await this.#getResourceById(q, resourceId);
|
|
13073
13213
|
if (!existingResource) {
|
|
13074
13214
|
const newResource = {
|
|
13075
13215
|
id: resourceId,
|
|
@@ -13078,7 +13218,7 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
13078
13218
|
createdAt: /* @__PURE__ */ new Date(),
|
|
13079
13219
|
updatedAt: /* @__PURE__ */ new Date()
|
|
13080
13220
|
};
|
|
13081
|
-
return this
|
|
13221
|
+
return this.#insertResource(q, newResource);
|
|
13082
13222
|
}
|
|
13083
13223
|
const updatedResource = {
|
|
13084
13224
|
...existingResource,
|
|
@@ -13114,7 +13254,7 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
13114
13254
|
updates.push(`"updatedAtZ" = $${paramIndex++}`);
|
|
13115
13255
|
values.push(updatedAtStr);
|
|
13116
13256
|
values.push(resourceId);
|
|
13117
|
-
await
|
|
13257
|
+
await q.none(`UPDATE ${tableName} SET ${updates.join(", ")} WHERE id = $${paramIndex}`, values);
|
|
13118
13258
|
return metadataJson ? {
|
|
13119
13259
|
...updatedResource,
|
|
13120
13260
|
metadata: JSON.parse(metadataJson)
|
|
@@ -13253,9 +13393,11 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
13253
13393
|
* serializes generation creation across processes instead. It is
|
|
13254
13394
|
* transaction-scoped so it also works behind transaction-pooling proxies.
|
|
13255
13395
|
*/
|
|
13256
|
-
async #withOMLookupKeyLock(tableName, lookupKey, fn) {
|
|
13396
|
+
async #withOMLookupKeyLock(tableName, lookupKey, fn, fencedOperation) {
|
|
13397
|
+
const fence = fencedOperation ? resolveRunFence(this, void 0) : void 0;
|
|
13257
13398
|
return this.#db.client.tx(async (t) => {
|
|
13258
13399
|
await t.query("SELECT pg_advisory_xact_lock(hashtextextended($1, 0))", [`${tableName}:${lookupKey}`]);
|
|
13400
|
+
if (fence && fencedOperation) await assertRunFence(t, this.#runFencesTable(), fence, fencedOperation);
|
|
13259
13401
|
return fn(t);
|
|
13260
13402
|
});
|
|
13261
13403
|
}
|
|
@@ -13552,7 +13694,7 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
13552
13694
|
const lastObservedAtStr = input.lastObservedAt.toISOString();
|
|
13553
13695
|
const nowStr = now.toISOString();
|
|
13554
13696
|
const observedMessageIdsJson = input.observedMessageIds ? toPgJson(input.observedMessageIds) : null;
|
|
13555
|
-
if ((await this.#
|
|
13697
|
+
if ((await this.#fenced(void 0, "updateActiveObservations", (q) => q.query(`UPDATE ${tableName} SET
|
|
13556
13698
|
"activeObservations" = $1,
|
|
13557
13699
|
"lastObservedAt" = $2,
|
|
13558
13700
|
"lastObservedAtZ" = $3,
|
|
@@ -13572,7 +13714,7 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
13572
13714
|
nowStr,
|
|
13573
13715
|
nowStr,
|
|
13574
13716
|
input.id
|
|
13575
|
-
])).rowCount === 0) throw new MastraError({
|
|
13717
|
+
]))).rowCount === 0) throw new MastraError({
|
|
13576
13718
|
id: createStorageErrorId("PG", "UPDATE_ACTIVE_OBSERVATIONS", "NOT_FOUND"),
|
|
13577
13719
|
text: `Observational memory record not found: ${input.id}`,
|
|
13578
13720
|
domain: ErrorDomain.STORAGE,
|
|
@@ -13580,7 +13722,7 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
13580
13722
|
details: { id: input.id }
|
|
13581
13723
|
});
|
|
13582
13724
|
} catch (error) {
|
|
13583
|
-
if (error instanceof MastraError) throw error;
|
|
13725
|
+
if (error instanceof MastraError || isRunFenceConflictError(error)) throw error;
|
|
13584
13726
|
throw new MastraError({
|
|
13585
13727
|
id: createStorageErrorId("PG", "UPDATE_ACTIVE_OBSERVATIONS", "FAILED"),
|
|
13586
13728
|
domain: ErrorDomain.STORAGE,
|
|
@@ -13600,8 +13742,9 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
13600
13742
|
const newer = await this.#getNewerOMGeneration(t, tableName, lookupKey, input.currentRecord.generationCount);
|
|
13601
13743
|
if (newer) return newer;
|
|
13602
13744
|
return this.#insertReflectionGeneration(t, tableName, lookupKey, input);
|
|
13603
|
-
});
|
|
13745
|
+
}, "createReflectionGeneration");
|
|
13604
13746
|
} catch (error) {
|
|
13747
|
+
if (isRunFenceConflictError(error)) throw error;
|
|
13605
13748
|
throw new MastraError({
|
|
13606
13749
|
id: createStorageErrorId("PG", "CREATE_REFLECTION_GENERATION", "FAILED"),
|
|
13607
13750
|
domain: ErrorDomain.STORAGE,
|
|
@@ -13961,7 +14104,7 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
13961
14104
|
extractionFailures: input.chunk.extractionFailures
|
|
13962
14105
|
};
|
|
13963
14106
|
const lastBufferedAtTime = input.lastBufferedAtTime ? input.lastBufferedAtTime.toISOString() : null;
|
|
13964
|
-
if ((await this.#
|
|
14107
|
+
if ((await this.#fenced(void 0, "updateBufferedObservations", (q) => q.query(`UPDATE ${tableName} SET
|
|
13965
14108
|
"bufferedObservationChunks" = CASE
|
|
13966
14109
|
WHEN EXISTS (
|
|
13967
14110
|
SELECT 1
|
|
@@ -13980,7 +14123,7 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
13980
14123
|
nowStr,
|
|
13981
14124
|
nowStr,
|
|
13982
14125
|
input.id
|
|
13983
|
-
])).rowCount === 0) throw new MastraError({
|
|
14126
|
+
]))).rowCount === 0) throw new MastraError({
|
|
13984
14127
|
id: createStorageErrorId("PG", "UPDATE_BUFFERED_OBSERVATIONS", "NOT_FOUND"),
|
|
13985
14128
|
text: `Observational memory record not found: ${input.id}`,
|
|
13986
14129
|
domain: ErrorDomain.STORAGE,
|
|
@@ -13988,7 +14131,7 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
13988
14131
|
details: { id: input.id }
|
|
13989
14132
|
});
|
|
13990
14133
|
} catch (error) {
|
|
13991
|
-
if (error instanceof MastraError) throw error;
|
|
14134
|
+
if (error instanceof MastraError || isRunFenceConflictError(error)) throw error;
|
|
13992
14135
|
throw new MastraError({
|
|
13993
14136
|
id: createStorageErrorId("PG", "UPDATE_BUFFERED_OBSERVATIONS", "FAILED"),
|
|
13994
14137
|
domain: ErrorDomain.STORAGE,
|
|
@@ -14070,7 +14213,7 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
14070
14213
|
const lastObservedAt = input.lastObservedAt ?? (latestChunk?.lastObservedAt ? new Date(latestChunk.lastObservedAt) : /* @__PURE__ */ new Date());
|
|
14071
14214
|
const lastObservedAtStr = lastObservedAt.toISOString();
|
|
14072
14215
|
const boundary = `\n\n--- message boundary (${lastObservedAt.toISOString()}) ---\n\n`;
|
|
14073
|
-
if ((await this.#
|
|
14216
|
+
if ((await this.#fenced(void 0, "swapBufferedToActive", (q) => q.query(`UPDATE ${tableName} SET
|
|
14074
14217
|
"activeObservations" = CASE
|
|
14075
14218
|
WHEN "activeObservations" IS NOT NULL AND "activeObservations" != ''
|
|
14076
14219
|
THEN "activeObservations" || $10 || $1
|
|
@@ -14096,7 +14239,7 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
14096
14239
|
nowStr,
|
|
14097
14240
|
input.id,
|
|
14098
14241
|
boundary
|
|
14099
|
-
])).rowCount === 0) return {
|
|
14242
|
+
]))).rowCount === 0) return {
|
|
14100
14243
|
chunksActivated: 0,
|
|
14101
14244
|
messageTokensActivated: 0,
|
|
14102
14245
|
observationTokensActivated: 0,
|
|
@@ -14124,7 +14267,7 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
14124
14267
|
currentTask: latestChunkHints?.currentTask ?? void 0
|
|
14125
14268
|
};
|
|
14126
14269
|
} catch (error) {
|
|
14127
|
-
if (error instanceof MastraError) throw error;
|
|
14270
|
+
if (error instanceof MastraError || isRunFenceConflictError(error)) throw error;
|
|
14128
14271
|
throw new MastraError({
|
|
14129
14272
|
id: createStorageErrorId("PG", "SWAP_BUFFERED_TO_ACTIVE", "FAILED"),
|
|
14130
14273
|
domain: ErrorDomain.STORAGE,
|
|
@@ -14140,7 +14283,7 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
14140
14283
|
schemaName: getSchemaName$3(this.#schema)
|
|
14141
14284
|
});
|
|
14142
14285
|
const nowStr = (/* @__PURE__ */ new Date()).toISOString();
|
|
14143
|
-
if ((await this.#
|
|
14286
|
+
if ((await this.#fenced(void 0, "updateBufferedReflection", (q) => q.query(`UPDATE ${tableName} SET
|
|
14144
14287
|
"bufferedReflection" = CASE
|
|
14145
14288
|
WHEN "bufferedReflection" IS NOT NULL AND "bufferedReflection" != ''
|
|
14146
14289
|
THEN "bufferedReflection" || E'\\n\\n' || $1
|
|
@@ -14159,7 +14302,7 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
14159
14302
|
nowStr,
|
|
14160
14303
|
nowStr,
|
|
14161
14304
|
input.id
|
|
14162
|
-
])).rowCount === 0) throw new MastraError({
|
|
14305
|
+
]))).rowCount === 0) throw new MastraError({
|
|
14163
14306
|
id: createStorageErrorId("PG", "UPDATE_BUFFERED_REFLECTION", "NOT_FOUND"),
|
|
14164
14307
|
text: `Observational memory record not found: ${input.id}`,
|
|
14165
14308
|
domain: ErrorDomain.STORAGE,
|
|
@@ -14167,7 +14310,7 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
14167
14310
|
details: { id: input.id }
|
|
14168
14311
|
});
|
|
14169
14312
|
} catch (error) {
|
|
14170
|
-
if (error instanceof MastraError) throw error;
|
|
14313
|
+
if (error instanceof MastraError || isRunFenceConflictError(error)) throw error;
|
|
14171
14314
|
throw new MastraError({
|
|
14172
14315
|
id: createStorageErrorId("PG", "UPDATE_BUFFERED_REFLECTION", "FAILED"),
|
|
14173
14316
|
domain: ErrorDomain.STORAGE,
|
|
@@ -14224,9 +14367,9 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
|
|
|
14224
14367
|
input.currentRecord.id
|
|
14225
14368
|
]);
|
|
14226
14369
|
return newRecord;
|
|
14227
|
-
});
|
|
14370
|
+
}, "swapBufferedReflectionToActive");
|
|
14228
14371
|
} catch (error) {
|
|
14229
|
-
if (error instanceof MastraError) throw error;
|
|
14372
|
+
if (error instanceof MastraError || isRunFenceConflictError(error)) throw error;
|
|
14230
14373
|
throw new MastraError({
|
|
14231
14374
|
id: createStorageErrorId("PG", "SWAP_BUFFERED_REFLECTION_TO_ACTIVE", "FAILED"),
|
|
14232
14375
|
domain: ErrorDomain.STORAGE,
|
|
@@ -21222,6 +21365,7 @@ var PromptBlocksPG = class PromptBlocksPG extends PromptBlocksStorage {
|
|
|
21222
21365
|
}
|
|
21223
21366
|
async create(input) {
|
|
21224
21367
|
const { promptBlock } = input;
|
|
21368
|
+
let draftInserted = false;
|
|
21225
21369
|
try {
|
|
21226
21370
|
const tableName = getTableName$5({
|
|
21227
21371
|
indexName: TABLE_PROMPT_BLOCKS,
|
|
@@ -21243,6 +21387,7 @@ var PromptBlocksPG = class PromptBlocksPG extends PromptBlocksStorage {
|
|
|
21243
21387
|
nowIso,
|
|
21244
21388
|
nowIso
|
|
21245
21389
|
]);
|
|
21390
|
+
draftInserted = true;
|
|
21246
21391
|
const { id: _id, authorId: _authorId, metadata: _metadata, ...snapshotConfig } = promptBlock;
|
|
21247
21392
|
const versionId = crypto.randomUUID();
|
|
21248
21393
|
await this.createVersion({
|
|
@@ -21263,14 +21408,14 @@ var PromptBlocksPG = class PromptBlocksPG extends PromptBlocksStorage {
|
|
|
21263
21408
|
updatedAt: now
|
|
21264
21409
|
};
|
|
21265
21410
|
} catch (error) {
|
|
21266
|
-
if (
|
|
21267
|
-
try {
|
|
21411
|
+
if (draftInserted) try {
|
|
21268
21412
|
const tableName = getTableName$5({
|
|
21269
21413
|
indexName: TABLE_PROMPT_BLOCKS,
|
|
21270
21414
|
schemaName: getSchemaName$5(this.#schema)
|
|
21271
21415
|
});
|
|
21272
21416
|
await this.#db.client.none(`DELETE FROM ${tableName} WHERE id = $1 AND status = 'draft' AND "activeVersionId" IS NULL`, [promptBlock.id]);
|
|
21273
21417
|
} catch {}
|
|
21418
|
+
if (error instanceof MastraError) throw error;
|
|
21274
21419
|
throw new MastraError({
|
|
21275
21420
|
id: createStorageErrorId("PG", "CREATE_PROMPT_BLOCK", "FAILED"),
|
|
21276
21421
|
domain: ErrorDomain.STORAGE,
|
|
@@ -22166,6 +22311,7 @@ var ScorerDefinitionsPG = class ScorerDefinitionsPG extends ScorerDefinitionsSto
|
|
|
22166
22311
|
}
|
|
22167
22312
|
async create(input) {
|
|
22168
22313
|
const { scorerDefinition } = input;
|
|
22314
|
+
let draftInserted = false;
|
|
22169
22315
|
try {
|
|
22170
22316
|
const tableName = getTableName$5({
|
|
22171
22317
|
indexName: TABLE_SCORER_DEFINITIONS,
|
|
@@ -22189,6 +22335,7 @@ var ScorerDefinitionsPG = class ScorerDefinitionsPG extends ScorerDefinitionsSto
|
|
|
22189
22335
|
nowIso,
|
|
22190
22336
|
nowIso
|
|
22191
22337
|
]);
|
|
22338
|
+
draftInserted = true;
|
|
22192
22339
|
const { id: _id, authorId: _authorId, organizationId: _organizationId, projectId: _projectId, metadata: _metadata, ...snapshotConfig } = scorerDefinition;
|
|
22193
22340
|
const versionId = crypto.randomUUID();
|
|
22194
22341
|
await this.createVersion({
|
|
@@ -22211,7 +22358,7 @@ var ScorerDefinitionsPG = class ScorerDefinitionsPG extends ScorerDefinitionsSto
|
|
|
22211
22358
|
updatedAt: now
|
|
22212
22359
|
};
|
|
22213
22360
|
} catch (error) {
|
|
22214
|
-
try {
|
|
22361
|
+
if (draftInserted) try {
|
|
22215
22362
|
const tableName = getTableName$5({
|
|
22216
22363
|
indexName: TABLE_SCORER_DEFINITIONS,
|
|
22217
22364
|
schemaName: getSchemaName$5(this.#schema)
|
|
@@ -23229,6 +23376,7 @@ var SkillsPG = class SkillsPG extends SkillsStorage {
|
|
|
23229
23376
|
}
|
|
23230
23377
|
async create(input) {
|
|
23231
23378
|
const { skill } = input;
|
|
23379
|
+
let draftInserted = false;
|
|
23232
23380
|
try {
|
|
23233
23381
|
const tableName = getTableName$5({
|
|
23234
23382
|
indexName: TABLE_SKILLS,
|
|
@@ -23252,6 +23400,7 @@ var SkillsPG = class SkillsPG extends SkillsStorage {
|
|
|
23252
23400
|
nowIso,
|
|
23253
23401
|
nowIso
|
|
23254
23402
|
]);
|
|
23403
|
+
draftInserted = true;
|
|
23255
23404
|
const { id: _id, authorId: _authorId, visibility: _visibility, ...snapshotConfig } = skill;
|
|
23256
23405
|
const versionId = crypto.randomUUID();
|
|
23257
23406
|
await this.createVersion({
|
|
@@ -23273,7 +23422,7 @@ var SkillsPG = class SkillsPG extends SkillsStorage {
|
|
|
23273
23422
|
updatedAt: now
|
|
23274
23423
|
};
|
|
23275
23424
|
} catch (error) {
|
|
23276
|
-
try {
|
|
23425
|
+
if (draftInserted) try {
|
|
23277
23426
|
const tableName = getTableName$5({
|
|
23278
23427
|
indexName: TABLE_SKILLS,
|
|
23279
23428
|
schemaName: getSchemaName$5(this.#schema)
|
|
@@ -24418,6 +24567,17 @@ function getTableName({ indexName, schemaName }) {
|
|
|
24418
24567
|
const quotedIndexName = `"${indexName}"`;
|
|
24419
24568
|
return schemaName ? `${schemaName}.${quotedIndexName}` : quotedIndexName;
|
|
24420
24569
|
}
|
|
24570
|
+
const RUN_OWNER_COLUMNS = `generation, "ownerId", "leaseExpiresAt", ${DB_NOW_MS} AS "nowMs"`;
|
|
24571
|
+
function toRunOwnershipRecord(runId, row) {
|
|
24572
|
+
const leaseExpiresAt = row.leaseExpiresAt === null ? null : Number(row.leaseExpiresAt);
|
|
24573
|
+
return {
|
|
24574
|
+
runId,
|
|
24575
|
+
generation: Number(row.generation),
|
|
24576
|
+
ownerId: row.ownerId,
|
|
24577
|
+
leaseExpiresAt: leaseExpiresAt === null ? null : new Date(leaseExpiresAt),
|
|
24578
|
+
live: leaseExpiresAt !== null && leaseExpiresAt > Number(row.nowMs)
|
|
24579
|
+
};
|
|
24580
|
+
}
|
|
24421
24581
|
/** Base name (before any schema prefix) of the expression index backing the status filter. */
|
|
24422
24582
|
const WORKFLOW_SNAPSHOT_STATUS_INDEX = "mastra_workflow_snapshot_name_status_createdat_idx";
|
|
24423
24583
|
/**
|
|
@@ -24502,12 +24662,24 @@ var WorkflowsPG = class WorkflowsPG extends WorkflowsStorage {
|
|
|
24502
24662
|
* Workflow run snapshots accumulate as runs execute. Anchored on the
|
|
24503
24663
|
* timezone-aware `updatedAtZ` mirror column (last activity) so suspended or
|
|
24504
24664
|
* long-running runs are not pruned by start age.
|
|
24665
|
+
*
|
|
24666
|
+
* Run ownership rows are anchored on `updatedAt` (epoch ms), which every
|
|
24667
|
+
* claim, renewal and release refreshes, so a live execution's row is never
|
|
24668
|
+
* older than its renew interval.
|
|
24505
24669
|
*/
|
|
24506
|
-
static retentionTables = {
|
|
24507
|
-
|
|
24508
|
-
|
|
24509
|
-
|
|
24510
|
-
|
|
24670
|
+
static retentionTables = {
|
|
24671
|
+
workflowSnapshot: {
|
|
24672
|
+
table: TABLE_WORKFLOW_SNAPSHOT,
|
|
24673
|
+
column: "updatedAtZ",
|
|
24674
|
+
indexed: true
|
|
24675
|
+
},
|
|
24676
|
+
runOwnership: {
|
|
24677
|
+
table: TABLE_WORKFLOW_RUN_OWNERS,
|
|
24678
|
+
column: "updatedAt",
|
|
24679
|
+
indexed: true,
|
|
24680
|
+
anchorType: "epoch-ms"
|
|
24681
|
+
}
|
|
24682
|
+
};
|
|
24511
24683
|
constructor(config) {
|
|
24512
24684
|
super();
|
|
24513
24685
|
const { client, readClient, schemaName, skipDefaultIndexes, indexes } = resolvePgConfig(config);
|
|
@@ -24564,6 +24736,12 @@ var WorkflowsPG = class WorkflowsPG extends WorkflowsStorage {
|
|
|
24564
24736
|
for (const idx of WorkflowsPG.getDefaultIndexDefs(schemaPrefix)) statements.push(generateIndexSQL(idx, schemaName));
|
|
24565
24737
|
statements.push(`${workflowSnapshotStatusIndexSQL(workflowSnapshotStatusIndexName(parsedSchema), schemaName)};`);
|
|
24566
24738
|
statements.push(`${workflowSnapshotThreadIdIndexSQL(workflowSnapshotThreadIdIndexName(parsedSchema), schemaName)};`);
|
|
24739
|
+
statements.push(generateTableSQL({
|
|
24740
|
+
tableName: TABLE_WORKFLOW_RUN_OWNERS,
|
|
24741
|
+
schema: RUN_FENCING_TABLE_SCHEMAS[TABLE_WORKFLOW_RUN_OWNERS],
|
|
24742
|
+
schemaName,
|
|
24743
|
+
includeAllConstraints: true
|
|
24744
|
+
}));
|
|
24567
24745
|
return statements;
|
|
24568
24746
|
}
|
|
24569
24747
|
/**
|
|
@@ -24607,6 +24785,10 @@ var WorkflowsPG = class WorkflowsPG extends WorkflowsStorage {
|
|
|
24607
24785
|
schema: TABLE_SCHEMAS[TABLE_WORKFLOW_SNAPSHOT],
|
|
24608
24786
|
ifNotExists: ["resourceId"]
|
|
24609
24787
|
});
|
|
24788
|
+
await this.#db.createTable({
|
|
24789
|
+
tableName: TABLE_WORKFLOW_RUN_OWNERS,
|
|
24790
|
+
schema: RUN_FENCING_TABLE_SCHEMAS[TABLE_WORKFLOW_RUN_OWNERS]
|
|
24791
|
+
});
|
|
24610
24792
|
await this.createDefaultIndexes();
|
|
24611
24793
|
await this.createCustomIndexes();
|
|
24612
24794
|
}
|
|
@@ -24634,13 +24816,13 @@ var WorkflowsPG = class WorkflowsPG extends WorkflowsStorage {
|
|
|
24634
24816
|
}
|
|
24635
24817
|
}
|
|
24636
24818
|
}
|
|
24637
|
-
/** Delete workflow run snapshots older than
|
|
24819
|
+
/** Delete workflow run snapshots and run ownership rows older than their policy's `maxAge`, batched. */
|
|
24638
24820
|
async prune(policies, options) {
|
|
24639
24821
|
await this.ensureRetentionIndexes(policies);
|
|
24640
24822
|
const targets = resolveTargets({
|
|
24641
24823
|
policies,
|
|
24642
24824
|
descriptor: WorkflowsPG.retentionTables,
|
|
24643
|
-
order: ["workflowSnapshot"]
|
|
24825
|
+
order: ["workflowSnapshot", "runOwnership"]
|
|
24644
24826
|
});
|
|
24645
24827
|
return runPrune({
|
|
24646
24828
|
db: this.#db,
|
|
@@ -24662,10 +24844,126 @@ var WorkflowsPG = class WorkflowsPG extends WorkflowsStorage {
|
|
|
24662
24844
|
}
|
|
24663
24845
|
async dangerouslyClearAll() {
|
|
24664
24846
|
await this.#db.clearTable({ tableName: TABLE_WORKFLOW_SNAPSHOT });
|
|
24847
|
+
await this.#db.clearTable({ tableName: TABLE_WORKFLOW_RUN_OWNERS });
|
|
24665
24848
|
}
|
|
24666
|
-
|
|
24849
|
+
supportsRunFencing() {
|
|
24850
|
+
return true;
|
|
24851
|
+
}
|
|
24852
|
+
#runOwnersTable() {
|
|
24853
|
+
return getTableName({
|
|
24854
|
+
indexName: TABLE_WORKFLOW_RUN_OWNERS,
|
|
24855
|
+
schemaName: getSchemaName(this.#schema)
|
|
24856
|
+
});
|
|
24857
|
+
}
|
|
24858
|
+
async #readRunOwner(q, runId) {
|
|
24859
|
+
const row = await q.oneOrNone(`SELECT ${RUN_OWNER_COLUMNS} FROM ${this.#runOwnersTable()} WHERE "runId" = $1`, [runId]);
|
|
24860
|
+
return row ? toRunOwnershipRecord(runId, row) : null;
|
|
24861
|
+
}
|
|
24862
|
+
#ownershipError(operation, runId, error) {
|
|
24863
|
+
return new MastraError({
|
|
24864
|
+
id: createStorageErrorId("PG", operation, "FAILED"),
|
|
24865
|
+
domain: ErrorDomain.STORAGE,
|
|
24866
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
24867
|
+
details: { runId }
|
|
24868
|
+
}, error);
|
|
24869
|
+
}
|
|
24870
|
+
async claimRunOwnership({ runId, ownerId, leaseMs, force, expectedGeneration }) {
|
|
24871
|
+
const table = this.#runOwnersTable();
|
|
24872
|
+
try {
|
|
24873
|
+
return await this.#db.client.tx(async (t) => {
|
|
24874
|
+
if (!await t.oneOrNone(`SELECT 1 FROM ${table} WHERE "runId" = $1 FOR UPDATE`, [runId])) {
|
|
24875
|
+
if (expectedGeneration !== void 0 && expectedGeneration !== 0) return {
|
|
24876
|
+
acquired: false,
|
|
24877
|
+
record: null
|
|
24878
|
+
};
|
|
24879
|
+
const inserted = await t.oneOrNone(`INSERT INTO ${table} ("runId", generation, "ownerId", "leaseExpiresAt", "updatedAt")
|
|
24880
|
+
VALUES ($1, GREATEST(1, ${DB_NOW_MS}), $2, ${DB_NOW_MS} + $3, ${DB_NOW_MS})
|
|
24881
|
+
ON CONFLICT ("runId") DO NOTHING
|
|
24882
|
+
RETURNING ${RUN_OWNER_COLUMNS}`, [
|
|
24883
|
+
runId,
|
|
24884
|
+
ownerId,
|
|
24885
|
+
leaseMs
|
|
24886
|
+
]);
|
|
24887
|
+
if (inserted) return {
|
|
24888
|
+
acquired: true,
|
|
24889
|
+
record: toRunOwnershipRecord(runId, inserted)
|
|
24890
|
+
};
|
|
24891
|
+
}
|
|
24892
|
+
const claimed = await t.oneOrNone(`UPDATE ${table}
|
|
24893
|
+
SET generation = generation + 1, "ownerId" = $2, "leaseExpiresAt" = ${DB_NOW_MS} + $3,
|
|
24894
|
+
"updatedAt" = ${DB_NOW_MS}
|
|
24895
|
+
WHERE "runId" = $1
|
|
24896
|
+
AND ($4::bigint IS NULL OR generation = $4)
|
|
24897
|
+
AND ($5::boolean OR "leaseExpiresAt" IS NULL OR "leaseExpiresAt" <= ${DB_NOW_MS})
|
|
24898
|
+
RETURNING ${RUN_OWNER_COLUMNS}`, [
|
|
24899
|
+
runId,
|
|
24900
|
+
ownerId,
|
|
24901
|
+
leaseMs,
|
|
24902
|
+
expectedGeneration ?? null,
|
|
24903
|
+
force === true
|
|
24904
|
+
]);
|
|
24905
|
+
if (claimed) return {
|
|
24906
|
+
acquired: true,
|
|
24907
|
+
record: toRunOwnershipRecord(runId, claimed)
|
|
24908
|
+
};
|
|
24909
|
+
return {
|
|
24910
|
+
acquired: false,
|
|
24911
|
+
record: await this.#readRunOwner(t, runId)
|
|
24912
|
+
};
|
|
24913
|
+
});
|
|
24914
|
+
} catch (error) {
|
|
24915
|
+
throw this.#ownershipError("CLAIM_RUN_OWNERSHIP", runId, error);
|
|
24916
|
+
}
|
|
24917
|
+
}
|
|
24918
|
+
async renewRunOwnership({ leaseMs, ...fence }) {
|
|
24919
|
+
try {
|
|
24920
|
+
const renewed = await this.#db.client.oneOrNone(`UPDATE ${this.#runOwnersTable()}
|
|
24921
|
+
SET "leaseExpiresAt" = ${DB_NOW_MS} + $4, "updatedAt" = ${DB_NOW_MS}
|
|
24922
|
+
WHERE "runId" = $1 AND generation = $2 AND "ownerId" = $3 AND "leaseExpiresAt" IS NOT NULL
|
|
24923
|
+
RETURNING ${RUN_OWNER_COLUMNS}`, [
|
|
24924
|
+
fence.runId,
|
|
24925
|
+
fence.generation,
|
|
24926
|
+
fence.ownerId,
|
|
24927
|
+
leaseMs
|
|
24928
|
+
]);
|
|
24929
|
+
if (renewed) return {
|
|
24930
|
+
renewed: true,
|
|
24931
|
+
record: toRunOwnershipRecord(fence.runId, renewed)
|
|
24932
|
+
};
|
|
24933
|
+
return {
|
|
24934
|
+
renewed: false,
|
|
24935
|
+
record: await this.#readRunOwner(this.#db.client, fence.runId)
|
|
24936
|
+
};
|
|
24937
|
+
} catch (error) {
|
|
24938
|
+
throw this.#ownershipError("RENEW_RUN_OWNERSHIP", fence.runId, error);
|
|
24939
|
+
}
|
|
24940
|
+
}
|
|
24941
|
+
async releaseRunOwnership(fence) {
|
|
24942
|
+
try {
|
|
24943
|
+
return await this.#db.client.oneOrNone(`UPDATE ${this.#runOwnersTable()}
|
|
24944
|
+
SET "leaseExpiresAt" = NULL, "updatedAt" = ${DB_NOW_MS}
|
|
24945
|
+
WHERE "runId" = $1 AND generation = $2 AND "ownerId" = $3
|
|
24946
|
+
RETURNING "runId"`, [
|
|
24947
|
+
fence.runId,
|
|
24948
|
+
fence.generation,
|
|
24949
|
+
fence.ownerId
|
|
24950
|
+
]) !== null;
|
|
24951
|
+
} catch (error) {
|
|
24952
|
+
throw this.#ownershipError("RELEASE_RUN_OWNERSHIP", fence.runId, error);
|
|
24953
|
+
}
|
|
24954
|
+
}
|
|
24955
|
+
async getRunOwnership({ runId }) {
|
|
24956
|
+
try {
|
|
24957
|
+
return await this.#readRunOwner(this.#db.client, runId);
|
|
24958
|
+
} catch (error) {
|
|
24959
|
+
throw this.#ownershipError("GET_RUN_OWNERSHIP", runId, error);
|
|
24960
|
+
}
|
|
24961
|
+
}
|
|
24962
|
+
async updateWorkflowResults({ workflowName, runId, stepId, result, requestContext, state, fence: explicitFence }) {
|
|
24963
|
+
const fence = resolveRunFence(this, explicitFence, runId);
|
|
24667
24964
|
try {
|
|
24668
24965
|
return await this.#db.client.tx(async (t) => {
|
|
24966
|
+
if (fence) await assertRunFence(t, this.#runOwnersTable(), fence, "updateWorkflowResults");
|
|
24669
24967
|
const tableName = getTableName({
|
|
24670
24968
|
indexName: TABLE_WORKFLOW_SNAPSHOT,
|
|
24671
24969
|
schemaName: getSchemaName(this.#schema)
|
|
@@ -24715,6 +25013,7 @@ var WorkflowsPG = class WorkflowsPG extends WorkflowsStorage {
|
|
|
24715
25013
|
return snapshot.context;
|
|
24716
25014
|
});
|
|
24717
25015
|
} catch (error) {
|
|
25016
|
+
if (isRunFenceConflictError(error)) throw error;
|
|
24718
25017
|
throw new MastraError({
|
|
24719
25018
|
id: createStorageErrorId("PG", "UPDATE_WORKFLOW_RESULTS", "FAILED"),
|
|
24720
25019
|
domain: ErrorDomain.STORAGE,
|
|
@@ -24727,9 +25026,11 @@ var WorkflowsPG = class WorkflowsPG extends WorkflowsStorage {
|
|
|
24727
25026
|
}, error);
|
|
24728
25027
|
}
|
|
24729
25028
|
}
|
|
24730
|
-
async updateWorkflowState({ workflowName, runId, opts }) {
|
|
25029
|
+
async updateWorkflowState({ workflowName, runId, opts, fence: explicitFence }) {
|
|
25030
|
+
const fence = resolveRunFence(this, explicitFence, runId);
|
|
24731
25031
|
try {
|
|
24732
25032
|
return await this.#db.client.tx(async (t) => {
|
|
25033
|
+
if (fence) await assertRunFence(t, this.#runOwnersTable(), fence, "updateWorkflowState");
|
|
24733
25034
|
const tableName = getTableName({
|
|
24734
25035
|
indexName: TABLE_WORKFLOW_SNAPSHOT,
|
|
24735
25036
|
schemaName: getSchemaName(this.#schema)
|
|
@@ -24759,6 +25060,7 @@ var WorkflowsPG = class WorkflowsPG extends WorkflowsStorage {
|
|
|
24759
25060
|
return updatedSnapshot;
|
|
24760
25061
|
});
|
|
24761
25062
|
} catch (error) {
|
|
25063
|
+
if (isRunFenceConflictError(error)) throw error;
|
|
24762
25064
|
throw new MastraError({
|
|
24763
25065
|
id: createStorageErrorId("PG", "UPDATE_WORKFLOW_STATE", "FAILED"),
|
|
24764
25066
|
domain: ErrorDomain.STORAGE,
|
|
@@ -24770,13 +25072,13 @@ var WorkflowsPG = class WorkflowsPG extends WorkflowsStorage {
|
|
|
24770
25072
|
}, error);
|
|
24771
25073
|
}
|
|
24772
25074
|
}
|
|
24773
|
-
async persistWorkflowSnapshot({ workflowName, runId, resourceId, snapshot, createdAt, updatedAt }) {
|
|
25075
|
+
async persistWorkflowSnapshot({ workflowName, runId, resourceId, snapshot, createdAt, updatedAt, fence }) {
|
|
24774
25076
|
try {
|
|
24775
25077
|
const now = /* @__PURE__ */ new Date();
|
|
24776
25078
|
const createdAtValue = createdAt ? createdAt : now;
|
|
24777
25079
|
const updatedAtValue = updatedAt ? updatedAt : now;
|
|
24778
25080
|
const sanitizedSnapshot = toPgJson(snapshot);
|
|
24779
|
-
await this.#db.client.none(`INSERT INTO ${getTableName({
|
|
25081
|
+
await withRunFence(this.#db.client, this.#runOwnersTable(), resolveRunFence(this, fence, runId), "persistWorkflowSnapshot", (q) => q.none(`INSERT INTO ${getTableName({
|
|
24780
25082
|
indexName: TABLE_WORKFLOW_SNAPSHOT,
|
|
24781
25083
|
schemaName: getSchemaName(this.#schema)
|
|
24782
25084
|
})} AS t
|
|
@@ -24792,8 +25094,9 @@ var WorkflowsPG = class WorkflowsPG extends WorkflowsStorage {
|
|
|
24792
25094
|
updatedAtValue,
|
|
24793
25095
|
createdAtValue,
|
|
24794
25096
|
updatedAtValue
|
|
24795
|
-
]);
|
|
25097
|
+
]));
|
|
24796
25098
|
} catch (error) {
|
|
25099
|
+
if (isRunFenceConflictError(error)) throw error;
|
|
24797
25100
|
throw new MastraError({
|
|
24798
25101
|
id: createStorageErrorId("PG", "PERSIST_WORKFLOW_SNAPSHOT", "FAILED"),
|
|
24799
25102
|
domain: ErrorDomain.STORAGE,
|
|
@@ -24859,13 +25162,14 @@ var WorkflowsPG = class WorkflowsPG extends WorkflowsStorage {
|
|
|
24859
25162
|
}, error);
|
|
24860
25163
|
}
|
|
24861
25164
|
}
|
|
24862
|
-
async deleteWorkflowRunById({ runId, workflowName }) {
|
|
25165
|
+
async deleteWorkflowRunById({ runId, workflowName, fence }) {
|
|
24863
25166
|
try {
|
|
24864
|
-
await this.#db.client.none(`DELETE FROM ${getTableName({
|
|
25167
|
+
await withRunFence(this.#db.client, this.#runOwnersTable(), resolveRunFence(this, fence, runId), "deleteWorkflowRunById", (q) => q.none(`DELETE FROM ${getTableName({
|
|
24865
25168
|
indexName: TABLE_WORKFLOW_SNAPSHOT,
|
|
24866
25169
|
schemaName: getSchemaName(this.#schema)
|
|
24867
|
-
})} WHERE run_id = $1 AND workflow_name = $2`, [runId, workflowName]);
|
|
25170
|
+
})} WHERE run_id = $1 AND workflow_name = $2`, [runId, workflowName]));
|
|
24868
25171
|
} catch (error) {
|
|
25172
|
+
if (isRunFenceConflictError(error)) throw error;
|
|
24869
25173
|
throw new MastraError({
|
|
24870
25174
|
id: createStorageErrorId("PG", "DELETE_WORKFLOW_RUN_BY_ID", "FAILED"),
|
|
24871
25175
|
domain: ErrorDomain.STORAGE,
|
|
@@ -25077,6 +25381,7 @@ var WorkspacesPG = class WorkspacesPG extends WorkspacesStorage {
|
|
|
25077
25381
|
}
|
|
25078
25382
|
async create(input) {
|
|
25079
25383
|
const { workspace } = input;
|
|
25384
|
+
let draftInserted = false;
|
|
25080
25385
|
try {
|
|
25081
25386
|
const tableName = getTableName$5({
|
|
25082
25387
|
indexName: TABLE_WORKSPACES,
|
|
@@ -25098,6 +25403,7 @@ var WorkspacesPG = class WorkspacesPG extends WorkspacesStorage {
|
|
|
25098
25403
|
nowIso,
|
|
25099
25404
|
nowIso
|
|
25100
25405
|
]);
|
|
25406
|
+
draftInserted = true;
|
|
25101
25407
|
const { id: _id, authorId: _authorId, metadata: _metadata, ...snapshotConfig } = workspace;
|
|
25102
25408
|
const versionId = crypto.randomUUID();
|
|
25103
25409
|
await this.createVersion({
|
|
@@ -25118,7 +25424,7 @@ var WorkspacesPG = class WorkspacesPG extends WorkspacesStorage {
|
|
|
25118
25424
|
updatedAt: now
|
|
25119
25425
|
};
|
|
25120
25426
|
} catch (error) {
|
|
25121
|
-
try {
|
|
25427
|
+
if (draftInserted) try {
|
|
25122
25428
|
const tableName = getTableName$5({
|
|
25123
25429
|
indexName: TABLE_WORKSPACES,
|
|
25124
25430
|
schemaName: getSchemaName$5(this.#schema)
|