durable-execution-orpc-utils
Version:
oRPC utilities for durable-execution to create a separate server process for durable execution
162 lines • 4.99 kB
JavaScript
// src/index.ts
import { safe, toORPCError } from "@orpc/client";
import {
ORPCError
} from "@orpc/contract";
import {
type
} from "@orpc/server";
import {
DurableExecutionError,
DurableExecutionNotFoundError
} from "durable-execution";
import { getErrorMessage } from "@gpahal/std/errors";
function createEnqueueTaskProcedure(osBuilder, executor, tasks) {
return osBuilder.input(
type()
).output(type()).handler(async ({ input }) => {
const task = tasks[input.taskId];
if (!task) {
throw new ORPCError("NOT_FOUND", {
message: `Task ${input.taskId} not found`
});
}
try {
const handle = await executor.enqueueTask(
task,
input.input,
input.options
);
return handle.executionId;
} catch (error) {
if (error instanceof DurableExecutionError) {
if (error instanceof DurableExecutionNotFoundError) {
throw new ORPCError("NOT_FOUND", {
message: error.message
});
}
throw new ORPCError(error.isInternal ? "INTERNAL_SERVER_ERROR" : "BAD_REQUEST", {
message: error.message
});
}
throw new ORPCError("INTERNAL_SERVER_ERROR", {
message: getErrorMessage(error)
});
}
});
}
function createGetTaskExecutionProcedure(osBuilder, executor, tasks) {
return osBuilder.input(
type()
).output(type()).handler(async ({ input }) => {
const task = tasks[input.taskId];
if (!task) {
throw new ORPCError("NOT_FOUND", {
message: `Task ${input.taskId} not found`
});
}
try {
const handle = await executor.getTaskExecutionHandle(task, input.executionId);
return await handle.getExecution();
} catch (error) {
if (error instanceof DurableExecutionError) {
if (error instanceof DurableExecutionNotFoundError) {
throw new ORPCError("NOT_FOUND", {
message: error.message
});
}
throw new ORPCError(error.isInternal ? "INTERNAL_SERVER_ERROR" : "BAD_REQUEST", {
message: error.message
});
}
throw new ORPCError("INTERNAL_SERVER_ERROR", {
message: getErrorMessage(error)
});
}
});
}
function createWakeupSleepingTaskExecutionProcedure(osBuilder, executor, tasks) {
return osBuilder.input(
type()
).output(type()).handler(async ({ input }) => {
const task = tasks[input.taskId];
if (!task) {
throw new ORPCError("NOT_FOUND", {
message: `Task ${input.taskId} not found`
});
}
if (task.taskType !== "sleepingTask") {
throw new ORPCError("BAD_REQUEST", {
message: `Task ${input.taskId} is not a sleeping task`
});
}
try {
return await executor.wakeupSleepingTaskExecution(
task,
input.sleepingTaskUniqueId,
input.options
);
} catch (error) {
if (error instanceof DurableExecutionError) {
if (error instanceof DurableExecutionNotFoundError) {
throw new ORPCError("NOT_FOUND", {
message: error.message
});
}
throw new ORPCError(error.isInternal ? "INTERNAL_SERVER_ERROR" : "BAD_REQUEST", {
message: error.message
});
}
throw new ORPCError("INTERNAL_SERVER_ERROR", {
message: getErrorMessage(error)
});
}
});
}
function createTasksRouter(osBuilder, executor, tasks) {
return {
enqueueTask: createEnqueueTaskProcedure(osBuilder, executor, tasks),
getTaskExecution: createGetTaskExecutionProcedure(osBuilder, executor, tasks),
wakeupSleepingTaskExecution: createWakeupSleepingTaskExecutionProcedure(
osBuilder,
executor,
tasks
)
};
}
var RETRYABLE_STATUSES = /* @__PURE__ */ new Set([408, 429, 500, 502, 503, 504]);
function convertProcedureClientToTask(executor, taskOptions, procedure, ...rest) {
return executor.task({
...taskOptions,
run: async (_, input) => {
const context = rest.length > 0 ? rest[0] : void 0;
const procedureRest = [input, context];
const { error, data, isSuccess } = await safe(procedure(...procedureRest));
if (error) {
const orpcError = toORPCError(error);
if (orpcError.status === 404) {
throw new DurableExecutionNotFoundError(orpcError.message);
}
let isRetryable = false;
let isInternal = false;
if (RETRYABLE_STATUSES.has(orpcError.status)) {
isRetryable = true;
}
if (orpcError.status >= 500) {
isInternal = true;
}
throw new DurableExecutionError(orpcError.message, { isRetryable, isInternal });
} else if (isSuccess) {
return data;
} else {
throw DurableExecutionError.nonRetryable("Unknown error");
}
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
});
}
export {
convertProcedureClientToTask,
createTasksRouter
};
//# sourceMappingURL=index.js.map