UNPKG

durable-execution-storage-convex

Version:

Convex storage implementation for durable-execution

884 lines (880 loc) 28.6 kB
// 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