1// Alchemy modifications are licensed under Apache-2.0.
2// This file includes third-party code; see /THIRD_PARTY_LICENSES.md.
3import type { ResolvedStepConfig } from "./context.ts";
4import type {
5 DatabaseInstance,
6 DatabaseVersion,
7 DatabaseWorkflow,
8} from "./engine.ts";
9import type { WorkflowEvent } from "cloudflare:workers";
10
11export type Instance = {
12 id: string;
13 created_on: string;
14 modified_on: string;
15 workflow_id: string;
16 version_id: string;
17 status: InstanceStatus;
18 started_on: string | null;
19 ended_on: string | null;
20};
21
22export const INSTANCE_METADATA = `INSTANCE_METADATA`;
23
24export type InstanceMetadata = {
25 accountId: number;
26 workflow: DatabaseWorkflow;
27 version: DatabaseVersion;
28 instance: DatabaseInstance;
29 event: WorkflowEvent<unknown>;
30};
31
32export enum InstanceStatus {
33 Queued = 0, // Queued and waiting to start
34 Running = 1,
35 Paused = 2, // TODO (WOR-73): Implement pause
36 Errored = 3, // Stopped due to a user or system Error
37 Terminated = 4, // Stopped explicitly by user
38 Complete = 5, // Successful completion
39 WaitingForPause = 6,
40 Waiting = 7,
41}
42
43export function instanceStatusName(status: InstanceStatus) {
44 switch (status) {
45 case InstanceStatus.Queued:
46 return "queued";
47 case InstanceStatus.Running:
48 return "running";
49 case InstanceStatus.Paused:
50 return "paused";
51 case InstanceStatus.Errored:
52 return "errored";
53 case InstanceStatus.Terminated:
54 return "terminated";
55 case InstanceStatus.Complete:
56 return "complete";
57 case InstanceStatus.WaitingForPause:
58 return "waitingForPause";
59 case InstanceStatus.Waiting:
60 return "waiting";
61 default:
62 return "unknown";
63 }
64}
65
66export const instanceStatusNames = [
67 "queued",
68 "running",
69 "paused",
70 "errored",
71 "terminated",
72 "complete",
73 "waitingForPause",
74 "waiting",
75 "unknown",
76] as const;
77
78export function toInstanceStatus(status: string): InstanceStatus {
79 switch (status) {
80 case "queued":
81 return InstanceStatus.Queued;
82 case "running":
83 return InstanceStatus.Running;
84 case "paused":
85 return InstanceStatus.Paused;
86 case "errored":
87 return InstanceStatus.Errored;
88 case "terminated":
89 return InstanceStatus.Terminated;
90 case "complete":
91 return InstanceStatus.Complete;
92 case "waitingForPause":
93 return InstanceStatus.WaitingForPause;
94 case "waiting":
95 return InstanceStatus.Waiting;
96 case "unknown":
97 throw new Error("unknown cannot be parsed into a InstanceStatus");
98 default:
99 throw new Error(
100 `${status} was not handled because it's not a valid InstanceStatus`,
101 );
102 }
103}
104
105export const enum InstanceEvent {
106 WORKFLOW_QUEUED = 0,
107 WORKFLOW_START = 1,
108 WORKFLOW_SUCCESS = 2,
109 WORKFLOW_FAILURE = 3,
110 WORKFLOW_TERMINATED = 4,
111
112 STEP_START = 5,
113 STEP_SUCCESS = 6,
114 STEP_FAILURE = 7,
115
116 SLEEP_START = 8,
117 SLEEP_COMPLETE = 9,
118
119 ATTEMPT_START = 10,
120 ATTEMPT_SUCCESS = 11,
121 ATTEMPT_FAILURE = 12,
122
123 // It's here just to make it sequential and to not have gaps in the event types.
124 __INTERNAL_PROD = 13,
125
126 WAIT_START = 14,
127 WAIT_COMPLETE = 15,
128 WAIT_TIMED_OUT = 16,
129
130 ROLLBACK_START = 17,
131 ROLLBACK_STEP_START = 18,
132 ROLLBACK_ATTEMPT_START = 19,
133 ROLLBACK_ATTEMPT_SUCCESS = 20,
134 ROLLBACK_ATTEMPT_FAILURE = 21,
135 ROLLBACK_STEP_SUCCESS = 22,
136 ROLLBACK_STEP_FAILURE = 23,
137 ROLLBACK_COMPLETE = 24,
138 ROLLBACK_FAILED = 25,
139
140 WORKFLOW_RUNNING = 26,
141 WORKFLOW_PAUSED = 27,
142 WORKFLOW_WAITING_FOR_PAUSE = 28,
143 WORKFLOW_WAITING = 29,
144}
145
146export const enum InstanceTrigger {
147 API = 0,
148 BINDING = 1,
149 EVENT = 2,
150 CRON = 3,
151}
152
153export function instanceTriggerName(trigger: InstanceTrigger) {
154 switch (trigger) {
155 case InstanceTrigger.API:
156 return "api";
157 case InstanceTrigger.BINDING:
158 return "binding";
159 case InstanceTrigger.EVENT:
160 return "event";
161 case InstanceTrigger.CRON:
162 return "cron";
163 default:
164 return "unknown";
165 }
166}
167
168export type RawInstanceLog = {
169 id: number;
170 timestamp: string;
171 event: InstanceEvent;
172 groupKey: string | null;
173 target: string | null;
174 metadata: string;
175};
176
177export type InstanceAttempt = {
178 start: string;
179 end: string | null;
180 success: boolean | null;
181 error: { name: string; message: string } | null;
182};
183
184export type InstanceStepLog = {
185 name: string;
186 start: string;
187 end: string | null;
188 attempts: Array<InstanceAttempt>;
189 config: ResolvedStepConfig;
190 output: unknown;
191 success: boolean | null;
192 type: "step";
193};
194
195export type InstanceSleepLog = {
196 name: string;
197 start: string;
198 end: string;
199 finished: boolean;
200 type: "sleep";
201};
202
203export type InstanceTerminateLog = {
204 type: "termination";
205 trigger: {
206 source: string;
207 };
208};
209
210export type InstanceLogsResponse = {
211 params: Record<string, unknown>;
212 trigger: {
213 source: ReturnType<typeof instanceTriggerName>;
214 };
215 versionId: string;
216 queued: string;
217 start: string | null;
218 end: string | null;
219 steps: Array<InstanceStepLog | InstanceSleepLog | InstanceTerminateLog>;
220 success: boolean | null;
221 error: { name: string; message: string } | null;
222 output: Rpc.Serializable<unknown>;
223};
224
225export type WakerPriorityEntry = {
226 hash: string;
227 type: WakerPriorityType;
228 targetTimestamp: number;
229};
230
231export type WakerPriorityType = "sleep" | "retry" | "timeout";