@cloudnux/local-cloud-provider 0.7.0 → 0.11.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.
@@ -81,7 +81,9 @@ interface SchedulerState {
81
81
  executionHistory: JobExecution[];
82
82
  isShuttingDown: boolean;
83
83
  runningExecutions: number;
84
- cleanupInterval?: NodeJS.Timeout;
84
+ tickInterval?: NodeJS.Timeout;
85
+ isDirty: boolean;
86
+ lastCleanupTime: number;
85
87
  lastRestartTime: Date;
86
88
  config: SchedulerConfig;
87
89
  }
@@ -867,12 +867,14 @@ var errorToString = (error) => {
867
867
 
868
868
  // ../../utils/src/logging/index.ts
869
869
  var currentLogLevel = logLevels[env("LOG_LEVEL")?.toLowerCase()] ?? logLevels.info;
870
+ var module = "default";
871
+ var requestId = "";
870
872
  var logger = {
871
873
  fatal: (message, meta) => {
872
874
  if (currentLogLevel >= logLevels.fatal) {
873
875
  console.error(
874
876
  `[${(/* @__PURE__ */ new Date()).toTimeString()}]`,
875
- `${chalk.bgRed.white(" fatal ")}${EOL}`,
877
+ `${chalk.bgRed.white(" fatal ")} - ${module || "unknown module"} - ${requestId || "no request ID"} - ${EOL}`,
876
878
  errorToString(message),
877
879
  meta ? `${EOL}${JSON.stringify(meta, null, 2)}` : ""
878
880
  );
@@ -882,7 +884,7 @@ var logger = {
882
884
  if (currentLogLevel >= logLevels.error) {
883
885
  console.error(
884
886
  `[${(/* @__PURE__ */ new Date()).toTimeString()}]`,
885
- `${chalk.bgRed.white(" error ")}${EOL}`,
887
+ `${chalk.bgRed.white(" error ")} - ${module || "unknown module"} - ${requestId || "no request ID"} - ${EOL}`,
886
888
  errorToString(message),
887
889
  meta ? `${EOL}${JSON.stringify(meta, null, 2)}` : ""
888
890
  );
@@ -892,7 +894,7 @@ var logger = {
892
894
  if (currentLogLevel >= logLevels.warn) {
893
895
  console.warn(
894
896
  `[${(/* @__PURE__ */ new Date()).toTimeString()}]`,
895
- `${chalk.bgYellow.black(" warn ")}${EOL}`,
897
+ `${chalk.bgYellow.black(" warn ")} - ${module || "unknown module"} - ${requestId || "no request ID"} - ${EOL}`,
896
898
  errorToString(message),
897
899
  meta ? `${EOL}${JSON.stringify(meta, null, 2)}` : ""
898
900
  );
@@ -902,7 +904,7 @@ var logger = {
902
904
  if (currentLogLevel >= logLevels.info) {
903
905
  console.info(
904
906
  `[${(/* @__PURE__ */ new Date()).toTimeString()}]`,
905
- `${chalk.bgBlue.white(" info ")}${EOL}`,
907
+ `${chalk.bgBlue.white(" info ")} - ${module || "unknown module"} - ${requestId || "no request ID"} - ${EOL}`,
906
908
  message,
907
909
  meta ? `${EOL}${JSON.stringify(meta, null, 2)}` : ""
908
910
  );
@@ -912,7 +914,7 @@ var logger = {
912
914
  if (currentLogLevel >= logLevels.debug) {
913
915
  console.debug(
914
916
  `[${(/* @__PURE__ */ new Date()).toTimeString()}]`,
915
- `${chalk.bgWhite.black(" debug ")}${EOL}`,
917
+ `${chalk.bgWhite.black(" debug ")} - ${module || "unknown module"} - ${requestId || "no request ID"} - ${EOL}`,
916
918
  message,
917
919
  meta ? `${EOL}${JSON.stringify(meta, null, 2)}` : ""
918
920
  );
@@ -1301,17 +1303,22 @@ var scheduleJob = (scheduler, state, executeJobFn) => {
1301
1303
  updatedScheduler.timerId = setTimeout(() => {
1302
1304
  executeJobFn(updatedScheduler);
1303
1305
  }, timeUntilNextRun);
1304
- logger.info(`${chalk3.blue("\u{1F4C5} Scheduled job")} ${chalk3.green(scheduler.job.name)} to run in ${chalk3.cyan(Math.round(timeUntilNextRun / 1e3))}s`);
1306
+ logger.debug(`${chalk3.blue("\u{1F4C5} Scheduled job")} ${chalk3.green(scheduler.job.name)} to run in ${chalk3.cyan(Math.round(timeUntilNextRun / 1e3))}s`);
1305
1307
  }
1306
1308
  return updatedScheduler;
1307
1309
  };
1308
1310
  var executeJobWithTimeout = async (handler, job, execution, timeoutMs) => {
1309
- return Promise.race([
1310
- handler(job, execution),
1311
- new Promise(
1312
- (_, reject) => setTimeout(() => reject(new Error("Job execution timeout")), timeoutMs)
1313
- )
1314
- ]);
1311
+ let timerId;
1312
+ try {
1313
+ return await Promise.race([
1314
+ handler(job, execution),
1315
+ new Promise((_, reject) => {
1316
+ timerId = setTimeout(() => reject(new Error("Job execution timeout")), timeoutMs);
1317
+ })
1318
+ ]);
1319
+ } finally {
1320
+ clearTimeout(timerId);
1321
+ }
1315
1322
  };
1316
1323
  var updateJobAfterExecution = (job, execution, config) => {
1317
1324
  const updatedJob = {
@@ -1354,7 +1361,7 @@ var saveSchedulerState = async (state) => {
1354
1361
  const tempFile = createTempFilePath(state.config.persistence.directory);
1355
1362
  await fs.writeFile(tempFile, JSON.stringify(serializedState, null, 2), "utf8");
1356
1363
  await fs.rename(tempFile, stateFile);
1357
- logger.info(`${logSymbols2.info} ${chalk4.blue("Enhanced scheduler state saved")}`);
1364
+ logger.debug(`${logSymbols2.info} ${chalk4.blue("Enhanced scheduler state saved")}`);
1358
1365
  } catch (error) {
1359
1366
  logger.error("Failed to save scheduler state:", error);
1360
1367
  }
@@ -1366,7 +1373,7 @@ var loadSchedulerStateData = async (directory) => {
1366
1373
  return JSON.parse(data);
1367
1374
  } catch (error) {
1368
1375
  if (error.code === "ENOENT") {
1369
- logger.info(`${chalk4.blue("No previous scheduler state found - starting fresh")}`);
1376
+ logger.debug(`${chalk4.blue("No previous scheduler state found - starting fresh")}`);
1370
1377
  } else {
1371
1378
  logger.error("Failed to load scheduler state:", error);
1372
1379
  }
@@ -1379,20 +1386,20 @@ var validateAndAdjustNextRun = (job, savedNextRun, lastRestartTime, config) => {
1379
1386
  return calculateNextRunFromLastRun(job, job.lastRun, config);
1380
1387
  }
1381
1388
  if (savedNextRun <= now) {
1382
- logger.info(`${chalk4.yellow("\u23F0 Saved next run is in the past for")} ${chalk4.green(job.name)} - recalculating`);
1389
+ logger.debug(`${chalk4.yellow("\u23F0 Saved next run is in the past for")} ${chalk4.green(job.name)} - recalculating`);
1383
1390
  return calculateNextRunFromLastRun(job, job.lastRun, config);
1384
1391
  }
1385
1392
  const timeSinceRestart = now.getTime() - lastRestartTime.getTime();
1386
1393
  const isRapidRestart = timeSinceRestart < config.restartBehavior.rapidRestartThreshold;
1387
1394
  if (isRapidRestart) {
1388
- logger.info(`${chalk4.blue("\u26A1 Rapid restart detected for")} ${chalk4.green(job.name)} - preserving saved timing`);
1395
+ logger.debug(`${chalk4.blue("\u26A1 Rapid restart detected for")} ${chalk4.green(job.name)} - preserving saved timing`);
1389
1396
  return savedNextRun;
1390
1397
  }
1391
1398
  if (job.cronExpression || job.intervalMs) {
1392
1399
  const expectedNextRun = calculateNextRunFromLastRun(job, job.lastRun, config);
1393
1400
  const timeDiff = Math.abs(savedNextRun.getTime() - expectedNextRun.getTime());
1394
1401
  if (timeDiff > config.restartBehavior.maxTimingDrift) {
1395
- logger.info(`${chalk4.yellow("\u{1F527} Adjusting timing for")} ${chalk4.green(job.name)} - drift of ${Math.round(timeDiff / 1e3)}s detected`);
1402
+ logger.debug(`${chalk4.yellow("\u{1F527} Adjusting timing for")} ${chalk4.green(job.name)} - drift of ${Math.round(timeDiff / 1e3)}s detected`);
1396
1403
  return expectedNextRun;
1397
1404
  }
1398
1405
  }
@@ -1406,7 +1413,7 @@ var restoreJobFromSavedData = (scheduler, savedJob, config, lastRestartTime) =>
1406
1413
  lastRun: savedJob.lastRun ? new Date(savedJob.lastRun) : void 0
1407
1414
  };
1408
1415
  if (definitionChanged) {
1409
- logger.info(`${chalk4.yellow("\u{1F504} Job definition changed:")} ${chalk4.green(savedJob.name)} - recalculating schedule`);
1416
+ logger.debug(`${chalk4.yellow("\u{1F504} Job definition changed:")} ${chalk4.green(savedJob.name)} - recalculating schedule`);
1410
1417
  updatedJob.nextRun = calculateNextRunFromLastRun(updatedJob, updatedJob.lastRun, config);
1411
1418
  } else {
1412
1419
  const savedNextRun = savedJob.nextRun ? new Date(savedJob.nextRun) : void 0;
@@ -1416,7 +1423,7 @@ var restoreJobFromSavedData = (scheduler, savedJob, config, lastRestartTime) =>
1416
1423
  const result = parseCronExpression(updatedJob.cronExpression, updatedJob.lastRun, {
1417
1424
  timezone: updatedJob.timezone
1418
1425
  });
1419
- logger.info(`${chalk4.blue("\u{1F4C5} Job restored:")} ${chalk4.green(savedJob.name)} - ${result.description} - next: ${chalk4.cyan(updatedJob.nextRun.toLocaleString())}`);
1426
+ logger.debug(`${chalk4.blue("\u{1F4C5} Job restored:")} ${chalk4.green(savedJob.name)} - ${result.description} - next: ${chalk4.cyan(updatedJob.nextRun.toLocaleString())}`);
1420
1427
  }
1421
1428
  return { ...scheduler, job: updatedJob };
1422
1429
  };
@@ -1459,16 +1466,11 @@ var cleanupExecutionHistory = (state) => {
1459
1466
  0,
1460
1467
  state.executionHistory.length - state.config.cleanup.maxExecutionHistory
1461
1468
  );
1462
- logger.info(`${chalk5.blue("\u{1F9F9} Cleaned up")} ${removed.length} old execution records`);
1469
+ logger.debug(`${chalk5.blue("\u{1F9F9} Cleaned up")} ${removed.length} old execution records`);
1463
1470
  return removed;
1464
1471
  }
1465
1472
  return [];
1466
1473
  };
1467
- var startCleanupInterval = (state) => {
1468
- return setInterval(() => {
1469
- cleanupExecutionHistory(state);
1470
- }, state.config.cleanup.cleanupInterval);
1471
- };
1472
1474
 
1473
1475
  // src/schedule-plugin/core.ts
1474
1476
  var DEFAULT_CONFIG = {
@@ -1520,6 +1522,8 @@ var createInitialState = (config) => {
1520
1522
  executionHistory: [],
1521
1523
  isShuttingDown: false,
1522
1524
  runningExecutions: 0,
1525
+ isDirty: false,
1526
+ lastCleanupTime: Date.now(),
1523
1527
  lastRestartTime: /* @__PURE__ */ new Date(),
1524
1528
  config
1525
1529
  };
@@ -1552,18 +1556,18 @@ var createSchedulerFunctions = (state) => {
1552
1556
  );
1553
1557
  const completedExecution = handleExecutionSuccess(execution, result);
1554
1558
  state.executions[execution.id] = completedExecution;
1555
- scheduler.job = updateJobAfterExecution(scheduler.job, execution, state.config);
1556
1559
  } catch (error) {
1557
1560
  const failedExecution = handleExecutionError(execution, error);
1558
1561
  state.executions[execution.id] = failedExecution;
1559
1562
  } finally {
1560
1563
  scheduler.isRunning = false;
1561
1564
  state.runningExecutions--;
1565
+ scheduler.job = updateJobAfterExecution(scheduler.job, execution, state.config);
1562
1566
  if (scheduler.job.enabled && !state.isShuttingDown) {
1563
1567
  scheduleJobFn(scheduler);
1564
1568
  }
1565
1569
  if (state.config.persistence.enabled) {
1566
- await saveSchedulerState(state);
1570
+ state.isDirty = true;
1567
1571
  }
1568
1572
  }
1569
1573
  };
@@ -1585,11 +1589,18 @@ var initializeScheduler = async (state, scheduleJobFn) => {
1585
1589
  );
1586
1590
  state.schedulers = schedulers;
1587
1591
  state.executionHistory = executionHistory;
1588
- if (state.config.persistence.saveInterval > 0) {
1589
- setInterval(() => saveSchedulerState(state), state.config.persistence.saveInterval);
1590
- }
1591
1592
  }
1592
- state.cleanupInterval = startCleanupInterval(state);
1593
+ const tickInterval = state.config.persistence.saveInterval > 0 ? state.config.persistence.saveInterval : state.config.cleanup.cleanupInterval;
1594
+ state.tickInterval = setInterval(async () => {
1595
+ if (state.isDirty && state.config.persistence.enabled) {
1596
+ state.isDirty = false;
1597
+ await saveSchedulerState(state);
1598
+ }
1599
+ if (Date.now() - state.lastCleanupTime >= state.config.cleanup.cleanupInterval) {
1600
+ state.lastCleanupTime = Date.now();
1601
+ cleanupExecutionHistory(state);
1602
+ }
1603
+ }, tickInterval);
1593
1604
  for (const scheduler of Object.values(state.schedulers)) {
1594
1605
  if (scheduler.job.enabled) {
1595
1606
  scheduleJobFn(scheduler);
@@ -1620,11 +1631,11 @@ var createJobFromDefinition = (jobDef, config) => {
1620
1631
  const result = parseCronExpression(cronExpression, void 0, {
1621
1632
  timezone: jobDef.timezone ?? config.cron.defaultTimezone
1622
1633
  });
1623
- logger.info(`${chalk7.blue("\u{1F4C5} Job")} ${chalk7.green(jobDef.name)}: ${result.description} - Next: ${chalk7.cyan(result.nextRun.toLocaleString())}`);
1634
+ logger.debug(`${chalk7.blue("\u{1F4C5} Job")} ${chalk7.green(jobDef.name)}: ${result.description} - Next: ${chalk7.cyan(result.nextRun.toLocaleString())}`);
1624
1635
  const upcoming = getNextExecutions(cronExpression, 3, {
1625
1636
  timezone: jobDef.timezone ?? config.cron.defaultTimezone
1626
1637
  });
1627
- logger.info(`${chalk7.blue(" Upcoming:")} ${upcoming.map((d) => d.toLocaleTimeString()).join(", ")}`);
1638
+ logger.debug(`${chalk7.blue(" Upcoming:")} ${upcoming.map((d) => d.toLocaleTimeString()).join(", ")}`);
1628
1639
  }
1629
1640
  const job = {
1630
1641
  id: generateJobId(),
@@ -1688,19 +1699,19 @@ var createExecutionsData = (state) => ({
1688
1699
  running: Object.values(state.executions).filter((e) => e.status === "running")
1689
1700
  });
1690
1701
  var registerDashboardRoute = (app, state) => {
1691
- app.get("/dashboard", async function(_, reply) {
1702
+ app.get("/schedule/dashboard", async function(_, reply) {
1692
1703
  const dashboardData = createDashboardData(state);
1693
1704
  return reply.status(200).send(dashboardData);
1694
1705
  });
1695
1706
  };
1696
1707
  var registerExecutionsRoute = (app, state) => {
1697
- app.get("/executions", async function(_, reply) {
1708
+ app.get("/schedule/executions", async function(_, reply) {
1698
1709
  const executionsData = createExecutionsData(state);
1699
1710
  return reply.status(200).send(executionsData);
1700
1711
  });
1701
1712
  };
1702
1713
  var registerTriggerJobRoute = (app, state, executeJobFn) => {
1703
- app.post("/jobs/:jobId/trigger", async function(request, reply) {
1714
+ app.post("/schedule/jobs/:jobId/trigger", async function(request, reply) {
1704
1715
  const scheduler = state.schedulers[request.params.jobId];
1705
1716
  if (!scheduler) {
1706
1717
  return reply.status(404).send({ error: "Job not found" });
@@ -1713,7 +1724,7 @@ var registerTriggerJobRoute = (app, state, executeJobFn) => {
1713
1724
  });
1714
1725
  };
1715
1726
  var registerEnableJobRoute = (app, state, scheduleJobFn) => {
1716
- app.put("/jobs/:jobId/enable", async function(request, reply) {
1727
+ app.put("/schedule/jobs/:jobId/enable", async function(request, reply) {
1717
1728
  const scheduler = state.schedulers[request.params.jobId];
1718
1729
  if (!scheduler) {
1719
1730
  return reply.status(404).send({ error: "Job not found" });
@@ -1725,7 +1736,7 @@ var registerEnableJobRoute = (app, state, scheduleJobFn) => {
1725
1736
  });
1726
1737
  };
1727
1738
  var registerDisableJobRoute = (app, state) => {
1728
- app.put("/jobs/:jobId/disable", async function(request, reply) {
1739
+ app.put("/schedule/jobs/:jobId/disable", async function(request, reply) {
1729
1740
  const scheduler = state.schedulers[request.params.jobId];
1730
1741
  if (!scheduler) {
1731
1742
  return reply.status(404).send({ error: "Job not found" });
@@ -1819,8 +1830,8 @@ var createSchedulerManager = ({
1819
1830
  return false;
1820
1831
  }
1821
1832
  };
1822
- const listJobs = (module) => {
1823
- return Object.values(state.schedulers).filter((s) => !module || s.job.module === module).map((s) => s.job.name).sort();
1833
+ const listJobs = (module2) => {
1834
+ return Object.values(state.schedulers).filter((s) => !module2 || s.job.module === module2).map((s) => s.job.name).sort();
1824
1835
  };
1825
1836
  const getJobStats = (jobName) => {
1826
1837
  try {
@@ -1839,7 +1850,7 @@ var createSchedulerManager = ({
1839
1850
  throw new Error(`Job '${jobName}' does not exist`);
1840
1851
  }
1841
1852
  if (scheduler.job.enabled) {
1842
- logger.info(`${logSymbols6.info} ${chalk8.blue("Job is already enabled:")} ${chalk8.magenta(jobName)}`);
1853
+ logger.debug(`${logSymbols6.info} ${chalk8.blue("Job is already enabled:")} ${chalk8.magenta(jobName)}`);
1843
1854
  return;
1844
1855
  }
1845
1856
  scheduler.job.enabled = true;
@@ -1858,7 +1869,7 @@ var createSchedulerManager = ({
1858
1869
  throw new Error(`Job '${jobName}' does not exist`);
1859
1870
  }
1860
1871
  if (!scheduler.job.enabled) {
1861
- logger.info(`${logSymbols6.info} ${chalk8.blue("Job is already disabled:")} ${chalk8.magenta(jobName)}`);
1872
+ logger.debug(`${logSymbols6.info} ${chalk8.blue("Job is already disabled:")} ${chalk8.magenta(jobName)}`);
1862
1873
  return;
1863
1874
  }
1864
1875
  scheduler.job.enabled = false;