@ontrails/cloudflare 1.0.0-beta.39 → 1.0.0-beta.41

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.
@@ -28,6 +28,8 @@ import type { ResolveHttpPermit } from '@ontrails/http';
28
28
 
29
29
  import { buildEnvResourceOverrides } from '../env.js';
30
30
  import type { WorkersEnv } from '../env.js';
31
+ import { createQueueHandler } from '../queues/index.js';
32
+ import type { CloudflareQueueBatch } from '../queues/index.js';
31
33
 
32
34
  export {
33
35
  buildEnvResourceOverrides,
@@ -89,6 +91,11 @@ export interface CloudflareWorker {
89
91
  env?: WorkersEnv | undefined,
90
92
  executionCtx?: WorkersExecutionContext | undefined
91
93
  ): Promise<Response>;
94
+ queue(
95
+ batch: CloudflareQueueBatch,
96
+ env?: WorkersEnv | undefined,
97
+ executionCtx?: WorkersExecutionContext | undefined
98
+ ): Promise<void>;
92
99
  }
93
100
 
94
101
  // ---------------------------------------------------------------------------
@@ -121,6 +128,18 @@ const mapCaughtError = (error: unknown): Response => {
121
128
  );
122
129
  };
123
130
 
131
+ const mapCaughtQueueError = (
132
+ error: unknown,
133
+ batch: CloudflareQueueBatch
134
+ ): void => {
135
+ const err = error instanceof Error ? error : new Error(String(error));
136
+ console.error(
137
+ '[ontrails:cloudflare/workers] Failed to materialize queue handler',
138
+ projectErrorDiagnostics(err)
139
+ );
140
+ batch.retryAll();
141
+ };
142
+
124
143
  // ---------------------------------------------------------------------------
125
144
  // createWorkersHandler
126
145
  // ---------------------------------------------------------------------------
@@ -128,7 +147,9 @@ const mapCaughtError = (error: unknown): Response => {
128
147
  const resolveResourceOverrides = (
129
148
  graph: Topo,
130
149
  env: WorkersEnv,
131
- options: CreateWorkersHandlerOptions
150
+ options: CreateWorkersHandlerOptions,
151
+ entrypoint: 'fetch' | 'queue',
152
+ queueName?: string
132
153
  ): ResourceOverrideMap => {
133
154
  // Explicit overrides are the documented escape hatch, so they resolve
134
155
  // first: an overridden resource never requires its env binding. Surface
@@ -139,10 +160,12 @@ const resolveResourceOverrides = (
139
160
  ? options.resources(env)
140
161
  : (options.resources ?? {});
141
162
  const envOverrides = buildEnvResourceOverrides(graph, env, {
163
+ entrypoint,
142
164
  except: Object.keys(userOverrides),
143
165
  exclude: options.exclude,
144
166
  include: options.include,
145
167
  intent: options.intent,
168
+ queue: queueName,
146
169
  });
147
170
  if (envOverrides.isErr()) {
148
171
  throw envOverrides.error;
@@ -155,6 +178,12 @@ interface MaterializedHandler {
155
178
  readonly handle: (request: Request) => Promise<Response>;
156
179
  }
157
180
 
181
+ interface MaterializedQueueHandler {
182
+ readonly env: WorkersEnv | undefined;
183
+ readonly handle: (batch: CloudflareQueueBatch) => Promise<void>;
184
+ readonly queue: string;
185
+ }
186
+
158
187
  /**
159
188
  * Build the `{ fetch }` Worker export for a topo.
160
189
  *
@@ -176,6 +205,7 @@ export const createWorkersHandler = (
176
205
  options: CreateWorkersHandlerOptions = {}
177
206
  ): CloudflareWorker => {
178
207
  let materialized: MaterializedHandler | undefined;
208
+ let materializedQueue: MaterializedQueueHandler | undefined;
179
209
 
180
210
  const handlerFor = (
181
211
  env: WorkersEnv | undefined
@@ -193,13 +223,44 @@ export const createWorkersHandler = (
193
223
  layers: options.layers,
194
224
  maxJsonBodyBytes: options.maxJsonBodyBytes,
195
225
  resolvePermit: options.resolvePermit,
196
- resources: resolveResourceOverrides(graph, env ?? {}, options),
226
+ resources: resolveResourceOverrides(graph, env ?? {}, options, 'fetch'),
197
227
  validate: options.validate,
198
228
  });
199
229
  materialized = { env, handle };
200
230
  return handle;
201
231
  };
202
232
 
233
+ const queueHandlerFor = (
234
+ env: WorkersEnv | undefined,
235
+ queueName: string
236
+ ): ((batch: CloudflareQueueBatch) => Promise<void>) => {
237
+ if (
238
+ materializedQueue !== undefined &&
239
+ materializedQueue.env === env &&
240
+ materializedQueue.queue === queueName
241
+ ) {
242
+ return materializedQueue.handle;
243
+ }
244
+ const handle = createQueueHandler(graph, {
245
+ configValues: options.configValues,
246
+ createContext: options.createContext,
247
+ exclude: options.exclude,
248
+ include: options.include,
249
+ intent: options.intent,
250
+ layers: options.layers,
251
+ resources: resolveResourceOverrides(
252
+ graph,
253
+ env ?? {},
254
+ options,
255
+ 'queue',
256
+ queueName
257
+ ),
258
+ validate: options.validate,
259
+ });
260
+ materializedQueue = { env, handle, queue: queueName };
261
+ return handle;
262
+ };
263
+
203
264
  return {
204
265
  fetch: async (request, env, _executionCtx) => {
205
266
  try {
@@ -208,5 +269,12 @@ export const createWorkersHandler = (
208
269
  return mapCaughtError(error);
209
270
  }
210
271
  },
272
+ queue: async (batch, env, _executionCtx) => {
273
+ try {
274
+ await queueHandlerFor(env, batch.queue)(batch);
275
+ } catch (error: unknown) {
276
+ mapCaughtQueueError(error, batch);
277
+ }
278
+ },
211
279
  };
212
280
  };