@cloudnux/local-cloud-provider 0.17.0 → 0.18.0

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.
@@ -1009,6 +1009,7 @@ import path3 from "path";
1009
1009
  import fastifyStatic from "@fastify/static";
1010
1010
  import fsPlugin4 from "fastify-plugin";
1011
1011
  import { createRequire } from "module";
1012
+ import { WebSocketConnectionGoneError as WebSocketConnectionGoneError2 } from "@cloudnux/core-cloud-provider";
1012
1013
 
1013
1014
  // src/queue-plugin/plugin.ts
1014
1015
  import fsPlugin from "fastify-plugin";
@@ -1048,16 +1049,40 @@ var createQueueService = (handler, module) => ({
1048
1049
  });
1049
1050
  var createQueueMessage = (body, headers) => {
1050
1051
  const id = Date.now().toString() + Math.random().toString(36).substring(2, 7);
1051
- return {
1052
+ const message = {
1052
1053
  id,
1053
1054
  timestamp: /* @__PURE__ */ new Date(),
1054
1055
  attempts: 0,
1055
1056
  payload: body,
1056
1057
  attributes: headers
1057
1058
  };
1059
+ const delaySeconds = Number(headers?.["x-delay-seconds"]);
1060
+ if (delaySeconds > 0) {
1061
+ message.nextAttempt = new Date(Date.now() + delaySeconds * 1e3);
1062
+ }
1063
+ return message;
1064
+ };
1065
+ var isMessageReady = (message, now = Date.now()) => {
1066
+ return !message.nextAttempt || message.nextAttempt.getTime() <= now;
1058
1067
  };
1059
1068
  var moveToProcessing = (queueService, batchSize) => {
1060
- return queueService.incoming.splice(0, batchSize);
1069
+ const now = Date.now();
1070
+ const ready = [];
1071
+ const remaining = [];
1072
+ for (const message of queueService.incoming) {
1073
+ if (ready.length < batchSize && isMessageReady(message, now)) {
1074
+ ready.push(message);
1075
+ } else {
1076
+ remaining.push(message);
1077
+ }
1078
+ }
1079
+ queueService.incoming = remaining;
1080
+ return ready;
1081
+ };
1082
+ var getNextReadyDelay = (queueService) => {
1083
+ const nextAttempts = queueService.incoming.filter((message) => message.nextAttempt).map((message) => message.nextAttempt.getTime());
1084
+ if (nextAttempts.length === 0) return null;
1085
+ return Math.max(0, Math.min(...nextAttempts) - Date.now());
1061
1086
  };
1062
1087
  var removeFromProcessing = (queueService, messageId) => {
1063
1088
  queueService.processing = queueService.processing.filter((msg) => msg.id !== messageId);
@@ -1168,7 +1193,7 @@ var handleProcessingError = async (queueName, message, queueService, config) =>
1168
1193
  }, delayMs);
1169
1194
  }
1170
1195
  };
1171
- var createBatchProcessor = (processMessage, config, dirtyQueues) => async (queueName, queueService) => {
1196
+ var createBatchProcessor = (processMessage, config, dirtyQueues, schedulerRef) => async (queueName, queueService) => {
1172
1197
  if (queueService.timeoutId) {
1173
1198
  clearTimeout(queueService.timeoutId);
1174
1199
  queueService.timeoutId = null;
@@ -1179,18 +1204,21 @@ var createBatchProcessor = (processMessage, config, dirtyQueues) => async (queue
1179
1204
  try {
1180
1205
  queueService.processingBatch = true;
1181
1206
  const messagesToProcess = moveToProcessing(queueService, config.batchSize);
1182
- if (messagesToProcess.length === 0) {
1183
- return;
1184
- }
1185
- queueService.processing.push(...messagesToProcess);
1186
- await Promise.all(messagesToProcess.map((message) => {
1187
- return processMessage(queueName, message, queueService);
1188
- }));
1189
- if (config.persistence.enabled && dirtyQueues) {
1190
- dirtyQueues.add(queueName);
1207
+ if (messagesToProcess.length > 0) {
1208
+ queueService.processing.push(...messagesToProcess);
1209
+ await Promise.all(messagesToProcess.map((message) => {
1210
+ return processMessage(queueName, message, queueService);
1211
+ }));
1212
+ if (config.persistence.enabled && dirtyQueues) {
1213
+ dirtyQueues.add(queueName);
1214
+ }
1191
1215
  }
1192
1216
  } finally {
1193
1217
  queueService.processingBatch = false;
1218
+ const nextReadyDelay = getNextReadyDelay(queueService);
1219
+ if (nextReadyDelay !== null) {
1220
+ schedulerRef?.current?.(queueName, queueService, nextReadyDelay);
1221
+ }
1194
1222
  }
1195
1223
  };
1196
1224
  var createProcessingScheduler = (processBatch, config) => (queueName, queueService, overrideDelay = null) => {
@@ -1601,12 +1629,15 @@ var queuesPlugin = fsPlugin(async (app, options) => {
1601
1629
  };
1602
1630
  const saveDirtyQueueStates = config.persistence.enabled && saveQueueState ? createDirtyQueuesStateSaver(saveQueueState, dirtyQueues)(queues) : async () => {
1603
1631
  };
1632
+ const schedulerRef = {};
1604
1633
  const processBatch = createBatchProcessor(
1605
1634
  processMessage,
1606
1635
  config,
1607
- config.persistence.enabled ? dirtyQueues : void 0
1636
+ config.persistence.enabled ? dirtyQueues : void 0,
1637
+ schedulerRef
1608
1638
  );
1609
1639
  const scheduleProcessing = createProcessingScheduler(processBatch, config);
1640
+ schedulerRef.current = scheduleProcessing;
1610
1641
  const loadQueueState = config.persistence.enabled ? createQueueStateLoader(
1611
1642
  config,
1612
1643
  scheduleProcessing,
@@ -2646,6 +2677,7 @@ var schedulerPlugin = fsPlugin2(async (app, options) => {
2646
2677
  import crypto from "crypto";
2647
2678
  import fsPlugin3 from "fastify-plugin";
2648
2679
  import websocketPlugin from "@fastify/websocket";
2680
+ import { WebSocketConnectionGoneError } from "@cloudnux/core-cloud-provider";
2649
2681
  var DEFAULT_CONFIG3 = {
2650
2682
  routeKeyField: "action"
2651
2683
  };
@@ -2752,7 +2784,7 @@ var websocketsPlugin = fsPlugin3(async (app, options) => {
2752
2784
  async sendToClient(connectionId, data) {
2753
2785
  const connection = connections.get(connectionId);
2754
2786
  if (!connection) {
2755
- throw new Error(`WebSocket connection ${connectionId} not found`);
2787
+ throw new WebSocketConnectionGoneError(connectionId);
2756
2788
  }
2757
2789
  const payload = typeof data === "string" ? data : JSON.stringify(data);
2758
2790
  connection.socket.send(payload);
@@ -2760,7 +2792,7 @@ var websocketsPlugin = fsPlugin3(async (app, options) => {
2760
2792
  async disconnect(connectionId) {
2761
2793
  const connection = connections.get(connectionId);
2762
2794
  if (!connection) {
2763
- throw new Error(`WebSocket connection ${connectionId} not found`);
2795
+ throw new WebSocketConnectionGoneError(connectionId);
2764
2796
  }
2765
2797
  connection.socket.close();
2766
2798
  }
@@ -2782,7 +2814,7 @@ var RouteRegistry = class _RouteRegistry {
2782
2814
  url: routeOptions.url,
2783
2815
  handler: routeOptions.handler?.name || "anonymous",
2784
2816
  registeredAt: /* @__PURE__ */ new Date(),
2785
- module: routeOptions.module
2817
+ module: routeOptions.config?.module
2786
2818
  };
2787
2819
  this.routes.push(routeInfo);
2788
2820
  }
@@ -3222,6 +3254,9 @@ async function devConsolePluginFunction(fastify, options = {}) {
3222
3254
  await wsManager.sendToClient(connectionId, request.body);
3223
3255
  return reply.status(200).send({ status: "success", message: `Message sent to ${connectionId}` });
3224
3256
  } catch (error) {
3257
+ if (error instanceof WebSocketConnectionGoneError2) {
3258
+ return reply.status(410).send({ error: error.message });
3259
+ }
3225
3260
  return reply.status(404).send({ error: error.message });
3226
3261
  }
3227
3262
  });