durable-execution-storage-convex
Version:
Convex storage implementation for durable-execution
884 lines (880 loc) • 28.6 kB
JavaScript
// src/client/index.ts
import {
actionGeneric,
mutationGeneric,
queryGeneric
} from "convex/server";
import {
DurableExecutionError
} from "durable-execution";
import { Either, Schema } from "effect";
// src/common.ts
import { v as v2 } from "convex/values";
import {
applyTaskExecutionStorageUpdate
} from "durable-execution";
import { omitUndefinedValues } from "@gpahal/std/objects";
// src/component/schema.ts
import { defineSchema, defineTable } from "convex/server";
import { v } from "convex/values";
var vDurableExecutionErrorType = v.union(
v.literal("generic"),
v.literal("not_found"),
v.literal("timed_out"),
v.literal("cancelled")
);
var vDurableExecutionError = v.object({
errorType: vDurableExecutionErrorType,
message: v.string(),
isRetryable: v.boolean(),
isInternal: v.boolean()
});
var vTaskExecutionStatus = v.union(
v.literal("ready"),
v.literal("running"),
v.literal("failed"),
v.literal("timed_out"),
v.literal("waiting_for_children"),
v.literal("waiting_for_finalize"),
v.literal("finalize_failed"),
v.literal("completed"),
v.literal("cancelled")
);
var vTaskExecutionOnChildrenFinishedProcessingStatus = v.union(
v.literal("idle"),
v.literal("processing"),
v.literal("processed")
);
var vTaskExecutionCloseStatus = v.union(
v.literal("idle"),
v.literal("ready"),
v.literal("closing"),
v.literal("closed")
);
var vTaskExecutionDBInsertValue = v.object({
shard: v.number(),
rootTaskId: v.optional(v.string()),
rootExecutionId: v.optional(v.string()),
parentTaskId: v.optional(v.string()),
parentExecutionId: v.optional(v.string()),
parentExecutionDocId: v.optional(v.id("taskExecutions")),
indexInParentChildren: v.optional(v.number()),
isOnlyChildOfParent: v.optional(v.boolean()),
isFinalizeOfParent: v.optional(v.boolean()),
taskId: v.string(),
executionId: v.string(),
isSleepingTask: v.boolean(),
sleepingTaskUniqueId: v.optional(v.string()),
retryOptions: v.object({
maxAttempts: v.number(),
baseDelayMs: v.optional(v.number()),
maxDelayMs: v.optional(v.number()),
delayMultiplier: v.optional(v.number())
}),
sleepMsBeforeRun: v.number(),
timeoutMs: v.number(),
areChildrenSequential: v.boolean(),
input: v.string(),
executorId: v.optional(v.string()),
status: vTaskExecutionStatus,
isFinished: v.boolean(),
runOutput: v.optional(v.string()),
output: v.optional(v.string()),
error: v.optional(vDurableExecutionError),
retryAttempts: v.number(),
startAt: v.number(),
startedAt: v.optional(v.number()),
expiresAt: v.optional(v.number()),
waitingForChildrenStartedAt: v.optional(v.number()),
waitingForFinalizeStartedAt: v.optional(v.number()),
finishedAt: v.optional(v.number()),
children: v.optional(
v.array(
v.object({
taskId: v.string(),
executionId: v.string()
})
)
),
acc: v.number(),
ocfpStatus: vTaskExecutionOnChildrenFinishedProcessingStatus,
ocfpExpiresAt: v.optional(v.number()),
ocfpFinishedAt: v.optional(v.number()),
finalize: v.optional(
v.object({
taskId: v.string(),
executionId: v.string()
})
),
closeStatus: vTaskExecutionCloseStatus,
closeExpiresAt: v.optional(v.number()),
closedAt: v.optional(v.number()),
npc: v.boolean(),
createdAt: v.number(),
updatedAt: v.number()
});
var schema_default = defineSchema({
taskExecutions: defineTable(vTaskExecutionDBInsertValue).index("by_executionId", ["executionId"]).index("by_sleepingTaskUniqueId", ["sleepingTaskUniqueId"]).index("by_shard_status_startAt", ["shard", "status", "startAt"]).index("by_shard_status_ocfpStatus_acc_updatedAt", [
"shard",
"status",
"ocfpStatus",
"acc",
"updatedAt"
]).index("by_shard_closeStatus_updatedAt", ["shard", "closeStatus", "updatedAt"]).index("by_status_isSleepingTask_expiresAt", ["status", "isSleepingTask", "expiresAt"]).index("by_ocfpExpiresAt", ["ocfpExpiresAt"]).index("by_closeExpiresAt", ["closeExpiresAt"]).index("by_shard_executorId_npc_updatedAt", ["shard", "executorId", "npc", "updatedAt"]).index("by_parentExecutionId_isFinished", ["parentExecutionId", "isFinished"]).index("by_shard_isFinished_closeStatus_updatedAt", [
"shard",
"isFinished",
"closeStatus",
"updatedAt"
]),
locks: defineTable({
key: v.string(),
expiresAt: v.number()
}).index("by_key", ["key"]).index("by_key_expiresAt", ["key", "expiresAt"])
});
// src/common.ts
var vTaskExecutionDBUpdateRequest = v2.object({
executorId: v2.optional(v2.string()),
status: v2.optional(vTaskExecutionStatus),
isFinished: v2.optional(v2.boolean()),
runOutput: v2.optional(v2.string()),
output: v2.optional(v2.string()),
error: v2.optional(vDurableExecutionError),
retryAttempts: v2.optional(v2.number()),
startAt: v2.optional(v2.number()),
startedAt: v2.optional(v2.number()),
expiresAt: v2.optional(v2.number()),
waitingForChildrenStartedAt: v2.optional(v2.number()),
waitingForFinalizeStartedAt: v2.optional(v2.number()),
finishedAt: v2.optional(v2.number()),
children: v2.optional(
v2.array(
v2.object({
taskId: v2.string(),
executionId: v2.string()
})
)
),
acc: v2.optional(v2.number()),
ocfpStatus: v2.optional(vTaskExecutionOnChildrenFinishedProcessingStatus),
ocfpExpiresAt: v2.optional(v2.number()),
ocfpFinishedAt: v2.optional(v2.number()),
finalize: v2.optional(
v2.object({
taskId: v2.string(),
executionId: v2.string()
})
),
closeStatus: v2.optional(vTaskExecutionCloseStatus),
closeExpiresAt: v2.optional(v2.number()),
closedAt: v2.optional(v2.number()),
npc: v2.optional(v2.boolean()),
updatedAt: v2.number(),
unset: v2.optional(
v2.object({
executorId: v2.optional(v2.boolean()),
runOutput: v2.optional(v2.boolean()),
error: v2.optional(v2.boolean()),
startedAt: v2.optional(v2.boolean()),
expiresAt: v2.optional(v2.boolean()),
ocfpExpiresAt: v2.optional(v2.boolean()),
closeExpiresAt: v2.optional(v2.boolean())
})
)
});
function taskExecutionStorageValueToDBInsertValue(value, shard) {
return {
shard,
rootTaskId: value.root?.taskId,
rootExecutionId: value.root?.executionId,
parentTaskId: value.parent?.taskId,
parentExecutionId: value.parent?.executionId,
indexInParentChildren: value.parent?.indexInParentChildren,
isOnlyChildOfParent: value.parent?.isOnlyChildOfParent,
isFinalizeOfParent: value.parent?.isFinalizeOfParent,
taskId: value.taskId,
executionId: value.executionId,
isSleepingTask: value.isSleepingTask,
sleepingTaskUniqueId: value.sleepingTaskUniqueId,
retryOptions: value.retryOptions,
sleepMsBeforeRun: value.sleepMsBeforeRun,
timeoutMs: value.timeoutMs,
areChildrenSequential: value.areChildrenSequential,
input: value.input,
executorId: value.executorId,
status: value.status,
isFinished: value.isFinished,
runOutput: value.runOutput,
output: value.output,
error: value.error,
retryAttempts: value.retryAttempts,
startAt: value.startAt,
startedAt: value.startedAt,
expiresAt: value.expiresAt,
waitingForChildrenStartedAt: value.waitingForChildrenStartedAt,
waitingForFinalizeStartedAt: value.waitingForFinalizeStartedAt,
finishedAt: value.finishedAt,
children: value.children,
acc: value.activeChildrenCount,
ocfpStatus: value.onChildrenFinishedProcessingStatus,
ocfpExpiresAt: value.onChildrenFinishedProcessingExpiresAt,
ocfpFinishedAt: value.onChildrenFinishedProcessingFinishedAt,
finalize: value.finalize,
closeStatus: value.closeStatus,
closeExpiresAt: value.closeExpiresAt,
closedAt: value.closedAt,
npc: value.needsPromiseCancellation,
createdAt: value.createdAt,
updatedAt: value.updatedAt
};
}
function taskExecutionDBValueToStorageValue(dbValue, update, updateExpiresAtWithStartedAt) {
const value = {
taskId: dbValue.taskId,
executionId: dbValue.executionId,
isSleepingTask: dbValue.isSleepingTask,
sleepingTaskUniqueId: dbValue.sleepingTaskUniqueId,
retryOptions: dbValue.retryOptions,
sleepMsBeforeRun: dbValue.sleepMsBeforeRun,
timeoutMs: dbValue.timeoutMs,
areChildrenSequential: dbValue.areChildrenSequential,
input: dbValue.input,
executorId: dbValue.executorId,
status: dbValue.status,
isFinished: dbValue.isFinished,
runOutput: dbValue.runOutput,
output: dbValue.output,
error: dbValue.error,
retryAttempts: dbValue.retryAttempts,
startAt: dbValue.startAt,
startedAt: dbValue.startedAt,
expiresAt: dbValue.expiresAt,
waitingForChildrenStartedAt: dbValue.waitingForChildrenStartedAt,
waitingForFinalizeStartedAt: dbValue.waitingForFinalizeStartedAt,
finishedAt: dbValue.finishedAt,
children: dbValue.children,
activeChildrenCount: dbValue.acc,
onChildrenFinishedProcessingStatus: dbValue.ocfpStatus,
onChildrenFinishedProcessingExpiresAt: dbValue.ocfpExpiresAt,
onChildrenFinishedProcessingFinishedAt: dbValue.ocfpFinishedAt,
finalize: dbValue.finalize,
closeStatus: dbValue.closeStatus,
closeExpiresAt: dbValue.closeExpiresAt,
closedAt: dbValue.closedAt,
needsPromiseCancellation: dbValue.npc,
createdAt: dbValue.createdAt,
updatedAt: dbValue.updatedAt
};
if (dbValue.rootTaskId && dbValue.rootExecutionId) {
value.root = {
taskId: dbValue.rootTaskId,
executionId: dbValue.rootExecutionId
};
}
if (dbValue.parentTaskId && dbValue.parentExecutionId) {
value.parent = {
taskId: dbValue.parentTaskId,
executionId: dbValue.parentExecutionId,
indexInParentChildren: dbValue.indexInParentChildren ?? 0,
isOnlyChildOfParent: dbValue.isOnlyChildOfParent ?? false,
isFinalizeOfParent: dbValue.isFinalizeOfParent ?? false
};
}
return update ? applyTaskExecutionStorageUpdate(value, update, updateExpiresAtWithStartedAt) : value;
}
function taskExecutionStorageUpdateToDBUpdateRequest(update) {
return omitUndefinedValues({
executorId: update.executorId,
status: update.status,
isFinished: update.isFinished,
runOutput: update.runOutput,
output: update.output,
error: update.error,
retryAttempts: update.retryAttempts,
startAt: update.startAt,
startedAt: update.startedAt,
expiresAt: update.expiresAt,
waitingForChildrenStartedAt: update.waitingForChildrenStartedAt,
waitingForFinalizeStartedAt: update.waitingForFinalizeStartedAt,
finishedAt: update.finishedAt,
children: update.children,
acc: update.activeChildrenCount,
ocfpStatus: update.onChildrenFinishedProcessingStatus,
ocfpExpiresAt: update.onChildrenFinishedProcessingExpiresAt,
ocfpFinishedAt: update.onChildrenFinishedProcessingFinishedAt,
finalize: update.finalize,
closeStatus: update.closeStatus,
closeExpiresAt: update.closeExpiresAt,
closedAt: update.closedAt,
npc: update.needsPromiseCancellation,
updatedAt: update.updatedAt,
unset: omitUndefinedValues({
executorId: update.unset?.executorId,
runOutput: update.unset?.runOutput,
error: update.unset?.error,
startedAt: update.unset?.startedAt,
expiresAt: update.unset?.expiresAt,
ocfpExpiresAt: update.unset?.onChildrenFinishedProcessingExpiresAt,
closeExpiresAt: update.unset?.closeExpiresAt
})
});
}
var vTaskExecutionStorageGetByIdFilters = v2.object({
isSleepingTask: v2.optional(v2.boolean()),
status: v2.optional(vTaskExecutionStatus),
isFinished: v2.optional(v2.boolean())
});
// src/client/index.ts
function convertDurableExecutionStorageComponentToPublicApiImpl(component, authSecret) {
const verifyArgs = (args) => {
if (!args?.authSecret) {
throw new Error("Invalid auth secret");
}
if (args.authSecret !== authSecret) {
throw new Error("Invalid auth secret");
}
return args.args;
};
const actionWithLock = async (ctx, key, fn, defaultValue) => {
const lockId = await ctx.runMutation(component.lib.acquireLock, { key });
if (!lockId) {
return defaultValue;
}
try {
return await fn();
} finally {
await ctx.runMutation(component.lib.releaseLock, { id: lockId });
}
};
return {
insertMany: mutationGeneric(
async (ctx, args) => {
await ctx.runMutation(
component.lib.insertMany,
verifyArgs(args)
);
}
),
getManyById: queryGeneric(
async (ctx, args) => {
return await ctx.runQuery(
component.lib.getManyById,
verifyArgs(args)
);
}
),
getManyBySleepingTaskUniqueId: queryGeneric(
async (ctx, args) => {
return await ctx.runQuery(
component.lib.getManyBySleepingTaskUniqueId,
verifyArgs(args)
);
}
),
updateManyById: actionGeneric(
async (ctx, args) => {
await ctx.runMutation(
component.lib.updateManyById,
verifyArgs(args)
);
}
),
updateManyByIdAndInsertChildrenIfUpdated: actionGeneric(
async (ctx, args) => {
await ctx.runMutation(
component.lib.updateManyByIdAndInsertChildrenIfUpdated,
verifyArgs(args)
);
}
),
updateByStatusAndStartAtLessThanAndReturn: actionGeneric(
async (ctx, args) => {
return await actionWithLock(
ctx,
`updateByStatusAndStartAtLessThanAndReturn_${args.args.shard}_${args.args.status}`,
() => {
return ctx.runMutation(
component.lib.updateByStatusAndStartAtLessThanAndReturn,
verifyArgs(args)
);
},
[]
);
}
),
updateByStatusAndOCFPStatusAndACCZeroAndReturn: actionGeneric(
async (ctx, args) => {
return await actionWithLock(
ctx,
`updateByStatusAndOCFPStatusAndACCZeroAndReturn_${args.args.shard}_${args.args.status}_${args.args.ocfpStatus}`,
() => {
return ctx.runMutation(
component.lib.updateByStatusAndOCFPStatusAndACCZeroAndReturn,
verifyArgs(args)
);
},
[]
);
}
),
updateByCloseStatusAndReturn: actionGeneric(
async (ctx, args) => {
return await actionWithLock(
ctx,
`updateByCloseStatusAndReturn_${args.args.shard}_${args.args.closeStatus}`,
() => {
return ctx.runMutation(component.lib.updateByCloseStatusAndReturn, verifyArgs(args));
},
[]
);
}
),
updateByStatusAndIsSleepingTaskAndExpiresAtLessThan: actionGeneric(
async (ctx, args) => {
return await actionWithLock(
ctx,
`updateByStatusAndIsSleepingTaskAndExpiresAtLessThan_${args.args.status}_${args.args.isSleepingTask}`,
() => {
return ctx.runMutation(
component.lib.updateByStatusAndIsSleepingTaskAndExpiresAtLessThan,
verifyArgs(args)
);
},
0
);
}
),
updateByOCFPExpiresAt: actionGeneric(
async (ctx, args) => {
return await actionWithLock(
ctx,
`updateByOCFPExpiresAt`,
() => {
return ctx.runMutation(component.lib.updateByOCFPExpiresAt, verifyArgs(args));
},
0
);
}
),
updateByCloseExpiresAt: actionGeneric(
async (ctx, args) => {
return await actionWithLock(
ctx,
`updateByCloseExpiresAt`,
() => {
return ctx.runMutation(component.lib.updateByCloseExpiresAt, verifyArgs(args));
},
0
);
}
),
updateByExecutorIdAndNPCAndReturn: actionGeneric(
async (ctx, args) => {
return await actionWithLock(
ctx,
`updateByExecutorIdAndNPCAndReturn_${args.args.shard}_${args.args.executorId}_${args.args.npc}`,
() => {
return ctx.runMutation(
component.lib.updateByExecutorIdAndNPCAndReturn,
verifyArgs(args)
);
},
[]
);
}
),
getManyByParentExecutionId: queryGeneric(
async (ctx, args) => {
return await ctx.runQuery(
component.lib.getManyByParentExecutionId,
verifyArgs(args)
);
}
),
updateManyByParentExecutionIdAndIsFinished: actionGeneric(
async (ctx, args) => {
await ctx.runMutation(
component.lib.updateManyByParentExecutionIdAndIsFinished,
verifyArgs(args)
);
}
),
updateAndDecrementParentACCByIsFinishedAndCloseStatus: actionGeneric(
async (ctx, args) => {
return await actionWithLock(
ctx,
`updateAndDecrementParentACCByIsFinishedAndCloseStatus_${args.args.shard}_${args.args.isFinished}_${args.args.closeStatus}`,
() => {
return ctx.runMutation(
component.lib.updateAndDecrementParentACCByIsFinishedAndCloseStatus,
verifyArgs(args)
);
},
0
);
}
),
deleteById: mutationGeneric(
async (ctx, args) => {
await ctx.runMutation(component.lib.deleteById, verifyArgs(args));
}
),
deleteAll: actionGeneric(async (ctx, args) => {
await ctx.runAction(component.lib.deleteAll, verifyArgs(args));
})
};
}
var ConvexTaskExecutionsStorageOptionsSchema = Schema.Struct({
totalShards: Schema.Int.pipe(
Schema.between(1, 64),
Schema.optionalWith({ nullable: true }),
Schema.withDecodingDefault(() => 1)
),
shards: Schema.Array(Schema.Int.pipe(Schema.greaterThanOrEqualTo(0))).pipe(
Schema.optionalWith({ nullable: true })
),
enableTestMode: Schema.Boolean.pipe(
Schema.optionalWith({ nullable: true }),
Schema.withDecodingDefault(() => false)
)
}).pipe(
Schema.filter((val) => {
if (val.shards?.some((shard) => shard < 0 || shard >= val.totalShards)) {
return `Shards must be an array of numbers between 0 and totalShards (${val.totalShards})`;
}
return true;
}),
Schema.transform(
Schema.Struct({
totalShards: Schema.Int,
shards: Schema.Array(Schema.Int),
enableTestMode: Schema.Boolean
}),
{
strict: true,
encode: (val) => ({
...val
}),
decode: (val) => {
let finalShards;
if (!val.shards) {
finalShards = Array.from({ length: val.totalShards }, (_, i) => i);
} else {
const shardsSet = new Set(val.shards);
finalShards = [...shardsSet].sort((a, b) => a - b);
}
return {
...val,
shards: finalShards
};
}
}
)
);
var ConvexTaskExecutionsStorage = class {
convexClient;
authSecret;
publicApi;
totalShards;
shards;
enableTestMode;
/**
* Creates a new task executions storage instance.
*
* @param convexClient - A Convex client that can be used to interact with the database.
* @param authSecret - The auth secret to use for the public API.
* @param publicApi - The public API to use. See
* {@link convertDurableExecutionStorageComponentToPublicApiImpl} for more details.
* @param options - An options object.
* @param options.totalShards - The total number of shards to use.
* @param options.shards - The shards to use. If not provided, all shards will be used.
* @param options.enableTestMode - Whether to enable test mode.
*/
constructor(convexClient, authSecret, publicApi, options = {}) {
const parsedOptions = Schema.decodeEither(ConvexTaskExecutionsStorageOptionsSchema)(options);
if (Either.isLeft(parsedOptions)) {
throw DurableExecutionError.nonRetryable(`Invalid options: ${parsedOptions.left.message}`);
}
this.convexClient = convexClient;
this.authSecret = authSecret;
this.publicApi = publicApi;
this.totalShards = parsedOptions.right.totalShards;
this.shards = parsedOptions.right.shards;
this.enableTestMode = parsedOptions.right.enableTestMode;
}
async insertMany(executions) {
if (executions.length === 0) {
return;
}
await this.convexClient.mutation(this.publicApi.insertMany, {
authSecret: this.authSecret,
args: {
executions: executions.map(
(value) => taskExecutionStorageValueToDBInsertValueWithShard(value, this.totalShards)
)
}
});
}
async getManyById(requests) {
const dbValues = await this.convexClient.query(this.publicApi.getManyById, {
authSecret: this.authSecret,
args: {
requests
}
});
return dbValues.map(
(dbValue) => dbValue ? taskExecutionDBValueToStorageValue(dbValue) : void 0
);
}
async getManyBySleepingTaskUniqueId(requests) {
const dbValues = await this.convexClient.query(this.publicApi.getManyBySleepingTaskUniqueId, {
authSecret: this.authSecret,
args: {
requests
}
});
return dbValues.map(
(dbValue) => dbValue ? taskExecutionDBValueToStorageValue(dbValue) : void 0
);
}
async updateManyById(requests) {
await this.convexClient.action(this.publicApi.updateManyById, {
authSecret: this.authSecret,
args: {
requests: requests.map((request) => ({
...request,
update: taskExecutionStorageUpdateToDBUpdateRequest(request.update)
}))
}
});
}
async updateManyByIdAndInsertChildrenIfUpdated(requests) {
await this.convexClient.action(this.publicApi.updateManyByIdAndInsertChildrenIfUpdated, {
authSecret: this.authSecret,
args: {
requests: requests.map((request) => ({
...request,
update: taskExecutionStorageUpdateToDBUpdateRequest(request.update),
childrenTaskExecutionsToInsertIfAnyUpdated: request.childrenTaskExecutionsToInsertIfAnyUpdated.map(
(value) => taskExecutionStorageValueToDBInsertValueWithShard(value, this.totalShards)
)
}))
}
});
}
async updateByStatusAndStartAtLessThanAndReturn({
status,
startAtLessThan,
update,
updateExpiresAtWithStartedAt,
limit
}) {
const dbValuesArr = await Promise.all(
this.shards.map(
(shard) => this.convexClient.action(this.publicApi.updateByStatusAndStartAtLessThanAndReturn, {
authSecret: this.authSecret,
args: {
shard,
status,
startAtLessThan,
update: taskExecutionStorageUpdateToDBUpdateRequest(update),
updateExpiresAtWithStartedAt,
limit
}
})
)
);
return dbValuesArr.flat().map(
(dbValue) => taskExecutionDBValueToStorageValue(dbValue, update, updateExpiresAtWithStartedAt)
);
}
async updateByStatusAndOnChildrenFinishedProcessingStatusAndActiveChildrenCountZeroAndReturn({
status,
onChildrenFinishedProcessingStatus,
update,
limit
}) {
const dbValuesArr = await Promise.all(
this.shards.map(
(shard) => this.convexClient.action(this.publicApi.updateByStatusAndOCFPStatusAndACCZeroAndReturn, {
authSecret: this.authSecret,
args: {
shard,
status,
ocfpStatus: onChildrenFinishedProcessingStatus,
update: taskExecutionStorageUpdateToDBUpdateRequest(update),
limit
}
})
)
);
return dbValuesArr.flat().map((dbValue) => taskExecutionDBValueToStorageValue(dbValue, update));
}
async updateByCloseStatusAndReturn({
closeStatus,
update,
limit
}) {
const dbValuesArr = await Promise.all(
this.shards.map(
(shard) => this.convexClient.action(this.publicApi.updateByCloseStatusAndReturn, {
authSecret: this.authSecret,
args: {
shard,
closeStatus,
update: taskExecutionStorageUpdateToDBUpdateRequest(update),
limit
}
})
)
);
return dbValuesArr.flat().map((dbValue) => taskExecutionDBValueToStorageValue(dbValue, update));
}
async updateByStatusAndIsSleepingTaskAndExpiresAtLessThan({
status,
isSleepingTask,
expiresAtLessThan,
update,
limit
}) {
return await this.convexClient.action(
this.publicApi.updateByStatusAndIsSleepingTaskAndExpiresAtLessThan,
{
authSecret: this.authSecret,
args: {
status,
isSleepingTask,
expiresAtLessThan,
update: taskExecutionStorageUpdateToDBUpdateRequest(update),
limit
}
}
);
}
async updateByOnChildrenFinishedProcessingExpiresAtLessThan({
onChildrenFinishedProcessingExpiresAtLessThan,
update,
limit
}) {
return await this.convexClient.action(this.publicApi.updateByOCFPExpiresAt, {
authSecret: this.authSecret,
args: {
ocfpExpiresAtLessThan: onChildrenFinishedProcessingExpiresAtLessThan,
update: taskExecutionStorageUpdateToDBUpdateRequest(update),
limit
}
});
}
async updateByCloseExpiresAtLessThan({
closeExpiresAtLessThan,
update,
limit
}) {
return await this.convexClient.action(this.publicApi.updateByCloseExpiresAt, {
authSecret: this.authSecret,
args: {
closeExpiresAtLessThan,
update: taskExecutionStorageUpdateToDBUpdateRequest(update),
limit
}
});
}
async updateByExecutorIdAndNeedsPromiseCancellationAndReturn({
executorId,
needsPromiseCancellation,
update,
limit
}) {
const dbValuesArr = await Promise.all(
this.shards.map(
(shard) => this.convexClient.action(this.publicApi.updateByExecutorIdAndNPCAndReturn, {
authSecret: this.authSecret,
args: {
shard,
executorId,
npc: needsPromiseCancellation,
update: taskExecutionStorageUpdateToDBUpdateRequest(update),
limit
}
})
)
);
return dbValuesArr.flat().map((dbValue) => taskExecutionDBValueToStorageValue(dbValue, update));
}
async getManyByParentExecutionId(requests) {
const dbValuesArr = await this.convexClient.query(this.publicApi.getManyByParentExecutionId, {
authSecret: this.authSecret,
args: {
requests
}
});
return dbValuesArr.map(
(dbValues) => dbValues.map((dbValue) => taskExecutionDBValueToStorageValue(dbValue))
);
}
async updateManyByParentExecutionIdAndIsFinished(requests) {
await this.convexClient.action(this.publicApi.updateManyByParentExecutionIdAndIsFinished, {
authSecret: this.authSecret,
args: {
requests: requests.map((request) => ({
...request,
update: taskExecutionStorageUpdateToDBUpdateRequest(request.update)
}))
}
});
}
async updateAndDecrementParentActiveChildrenCountByIsFinishedAndCloseStatus({
isFinished,
closeStatus,
update,
limit
}) {
const updatedCounts = await Promise.all(
this.shards.map(
(shard) => this.convexClient.action(
this.publicApi.updateAndDecrementParentACCByIsFinishedAndCloseStatus,
{
authSecret: this.authSecret,
args: {
shard,
isFinished,
closeStatus,
update: taskExecutionStorageUpdateToDBUpdateRequest(update),
limit: Math.ceil(limit / this.shards.length)
}
}
)
)
);
return updatedCounts.reduce((a, b) => a + b, 0);
}
async deleteById({ executionId }) {
if (!this.enableTestMode) {
return;
}
await this.convexClient.mutation(this.publicApi.deleteById, {
authSecret: this.authSecret,
args: {
executionId
}
});
}
async deleteAll() {
if (!this.enableTestMode) {
return;
}
await this.convexClient.action(this.publicApi.deleteAll, {
authSecret: this.authSecret,
args: void 0
});
}
};
function taskExecutionStorageValueToDBInsertValueWithShard(value, totalShards) {
const shard = Math.floor(Math.random() * totalShards);
return taskExecutionStorageValueToDBInsertValue(value, shard);
}
export {
ConvexTaskExecutionsStorage,
ConvexTaskExecutionsStorageOptionsSchema,
convertDurableExecutionStorageComponentToPublicApiImpl
};
//# sourceMappingURL=index.js.map