@cloudnux/local-cloud-provider 0.6.0 → 0.10.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
  }
@@ -1301,17 +1301,22 @@ var scheduleJob = (scheduler, state, executeJobFn) => {
1301
1301
  updatedScheduler.timerId = setTimeout(() => {
1302
1302
  executeJobFn(updatedScheduler);
1303
1303
  }, 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`);
1304
+ logger.debug(`${chalk3.blue("\u{1F4C5} Scheduled job")} ${chalk3.green(scheduler.job.name)} to run in ${chalk3.cyan(Math.round(timeUntilNextRun / 1e3))}s`);
1305
1305
  }
1306
1306
  return updatedScheduler;
1307
1307
  };
1308
1308
  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
- ]);
1309
+ let timerId;
1310
+ try {
1311
+ return await Promise.race([
1312
+ handler(job, execution),
1313
+ new Promise((_, reject) => {
1314
+ timerId = setTimeout(() => reject(new Error("Job execution timeout")), timeoutMs);
1315
+ })
1316
+ ]);
1317
+ } finally {
1318
+ clearTimeout(timerId);
1319
+ }
1315
1320
  };
1316
1321
  var updateJobAfterExecution = (job, execution, config) => {
1317
1322
  const updatedJob = {
@@ -1354,7 +1359,7 @@ var saveSchedulerState = async (state) => {
1354
1359
  const tempFile = createTempFilePath(state.config.persistence.directory);
1355
1360
  await fs.writeFile(tempFile, JSON.stringify(serializedState, null, 2), "utf8");
1356
1361
  await fs.rename(tempFile, stateFile);
1357
- logger.info(`${logSymbols2.info} ${chalk4.blue("Enhanced scheduler state saved")}`);
1362
+ logger.debug(`${logSymbols2.info} ${chalk4.blue("Enhanced scheduler state saved")}`);
1358
1363
  } catch (error) {
1359
1364
  logger.error("Failed to save scheduler state:", error);
1360
1365
  }
@@ -1366,7 +1371,7 @@ var loadSchedulerStateData = async (directory) => {
1366
1371
  return JSON.parse(data);
1367
1372
  } catch (error) {
1368
1373
  if (error.code === "ENOENT") {
1369
- logger.info(`${chalk4.blue("No previous scheduler state found - starting fresh")}`);
1374
+ logger.debug(`${chalk4.blue("No previous scheduler state found - starting fresh")}`);
1370
1375
  } else {
1371
1376
  logger.error("Failed to load scheduler state:", error);
1372
1377
  }
@@ -1379,20 +1384,20 @@ var validateAndAdjustNextRun = (job, savedNextRun, lastRestartTime, config) => {
1379
1384
  return calculateNextRunFromLastRun(job, job.lastRun, config);
1380
1385
  }
1381
1386
  if (savedNextRun <= now) {
1382
- logger.info(`${chalk4.yellow("\u23F0 Saved next run is in the past for")} ${chalk4.green(job.name)} - recalculating`);
1387
+ logger.debug(`${chalk4.yellow("\u23F0 Saved next run is in the past for")} ${chalk4.green(job.name)} - recalculating`);
1383
1388
  return calculateNextRunFromLastRun(job, job.lastRun, config);
1384
1389
  }
1385
1390
  const timeSinceRestart = now.getTime() - lastRestartTime.getTime();
1386
1391
  const isRapidRestart = timeSinceRestart < config.restartBehavior.rapidRestartThreshold;
1387
1392
  if (isRapidRestart) {
1388
- logger.info(`${chalk4.blue("\u26A1 Rapid restart detected for")} ${chalk4.green(job.name)} - preserving saved timing`);
1393
+ logger.debug(`${chalk4.blue("\u26A1 Rapid restart detected for")} ${chalk4.green(job.name)} - preserving saved timing`);
1389
1394
  return savedNextRun;
1390
1395
  }
1391
1396
  if (job.cronExpression || job.intervalMs) {
1392
1397
  const expectedNextRun = calculateNextRunFromLastRun(job, job.lastRun, config);
1393
1398
  const timeDiff = Math.abs(savedNextRun.getTime() - expectedNextRun.getTime());
1394
1399
  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`);
1400
+ logger.debug(`${chalk4.yellow("\u{1F527} Adjusting timing for")} ${chalk4.green(job.name)} - drift of ${Math.round(timeDiff / 1e3)}s detected`);
1396
1401
  return expectedNextRun;
1397
1402
  }
1398
1403
  }
@@ -1406,7 +1411,7 @@ var restoreJobFromSavedData = (scheduler, savedJob, config, lastRestartTime) =>
1406
1411
  lastRun: savedJob.lastRun ? new Date(savedJob.lastRun) : void 0
1407
1412
  };
1408
1413
  if (definitionChanged) {
1409
- logger.info(`${chalk4.yellow("\u{1F504} Job definition changed:")} ${chalk4.green(savedJob.name)} - recalculating schedule`);
1414
+ logger.debug(`${chalk4.yellow("\u{1F504} Job definition changed:")} ${chalk4.green(savedJob.name)} - recalculating schedule`);
1410
1415
  updatedJob.nextRun = calculateNextRunFromLastRun(updatedJob, updatedJob.lastRun, config);
1411
1416
  } else {
1412
1417
  const savedNextRun = savedJob.nextRun ? new Date(savedJob.nextRun) : void 0;
@@ -1416,7 +1421,7 @@ var restoreJobFromSavedData = (scheduler, savedJob, config, lastRestartTime) =>
1416
1421
  const result = parseCronExpression(updatedJob.cronExpression, updatedJob.lastRun, {
1417
1422
  timezone: updatedJob.timezone
1418
1423
  });
1419
- logger.info(`${chalk4.blue("\u{1F4C5} Job restored:")} ${chalk4.green(savedJob.name)} - ${result.description} - next: ${chalk4.cyan(updatedJob.nextRun.toLocaleString())}`);
1424
+ logger.debug(`${chalk4.blue("\u{1F4C5} Job restored:")} ${chalk4.green(savedJob.name)} - ${result.description} - next: ${chalk4.cyan(updatedJob.nextRun.toLocaleString())}`);
1420
1425
  }
1421
1426
  return { ...scheduler, job: updatedJob };
1422
1427
  };
@@ -1459,16 +1464,11 @@ var cleanupExecutionHistory = (state) => {
1459
1464
  0,
1460
1465
  state.executionHistory.length - state.config.cleanup.maxExecutionHistory
1461
1466
  );
1462
- logger.info(`${chalk5.blue("\u{1F9F9} Cleaned up")} ${removed.length} old execution records`);
1467
+ logger.debug(`${chalk5.blue("\u{1F9F9} Cleaned up")} ${removed.length} old execution records`);
1463
1468
  return removed;
1464
1469
  }
1465
1470
  return [];
1466
1471
  };
1467
- var startCleanupInterval = (state) => {
1468
- return setInterval(() => {
1469
- cleanupExecutionHistory(state);
1470
- }, state.config.cleanup.cleanupInterval);
1471
- };
1472
1472
 
1473
1473
  // src/schedule-plugin/core.ts
1474
1474
  var DEFAULT_CONFIG = {
@@ -1520,6 +1520,8 @@ var createInitialState = (config) => {
1520
1520
  executionHistory: [],
1521
1521
  isShuttingDown: false,
1522
1522
  runningExecutions: 0,
1523
+ isDirty: false,
1524
+ lastCleanupTime: Date.now(),
1523
1525
  lastRestartTime: /* @__PURE__ */ new Date(),
1524
1526
  config
1525
1527
  };
@@ -1552,18 +1554,18 @@ var createSchedulerFunctions = (state) => {
1552
1554
  );
1553
1555
  const completedExecution = handleExecutionSuccess(execution, result);
1554
1556
  state.executions[execution.id] = completedExecution;
1555
- scheduler.job = updateJobAfterExecution(scheduler.job, execution, state.config);
1556
1557
  } catch (error) {
1557
1558
  const failedExecution = handleExecutionError(execution, error);
1558
1559
  state.executions[execution.id] = failedExecution;
1559
1560
  } finally {
1560
1561
  scheduler.isRunning = false;
1561
1562
  state.runningExecutions--;
1563
+ scheduler.job = updateJobAfterExecution(scheduler.job, execution, state.config);
1562
1564
  if (scheduler.job.enabled && !state.isShuttingDown) {
1563
1565
  scheduleJobFn(scheduler);
1564
1566
  }
1565
1567
  if (state.config.persistence.enabled) {
1566
- await saveSchedulerState(state);
1568
+ state.isDirty = true;
1567
1569
  }
1568
1570
  }
1569
1571
  };
@@ -1585,11 +1587,18 @@ var initializeScheduler = async (state, scheduleJobFn) => {
1585
1587
  );
1586
1588
  state.schedulers = schedulers;
1587
1589
  state.executionHistory = executionHistory;
1588
- if (state.config.persistence.saveInterval > 0) {
1589
- setInterval(() => saveSchedulerState(state), state.config.persistence.saveInterval);
1590
- }
1591
1590
  }
1592
- state.cleanupInterval = startCleanupInterval(state);
1591
+ const tickInterval = state.config.persistence.saveInterval > 0 ? state.config.persistence.saveInterval : state.config.cleanup.cleanupInterval;
1592
+ state.tickInterval = setInterval(async () => {
1593
+ if (state.isDirty && state.config.persistence.enabled) {
1594
+ state.isDirty = false;
1595
+ await saveSchedulerState(state);
1596
+ }
1597
+ if (Date.now() - state.lastCleanupTime >= state.config.cleanup.cleanupInterval) {
1598
+ state.lastCleanupTime = Date.now();
1599
+ cleanupExecutionHistory(state);
1600
+ }
1601
+ }, tickInterval);
1593
1602
  for (const scheduler of Object.values(state.schedulers)) {
1594
1603
  if (scheduler.job.enabled) {
1595
1604
  scheduleJobFn(scheduler);
@@ -1620,11 +1629,11 @@ var createJobFromDefinition = (jobDef, config) => {
1620
1629
  const result = parseCronExpression(cronExpression, void 0, {
1621
1630
  timezone: jobDef.timezone ?? config.cron.defaultTimezone
1622
1631
  });
1623
- logger.info(`${chalk7.blue("\u{1F4C5} Job")} ${chalk7.green(jobDef.name)}: ${result.description} - Next: ${chalk7.cyan(result.nextRun.toLocaleString())}`);
1632
+ logger.debug(`${chalk7.blue("\u{1F4C5} Job")} ${chalk7.green(jobDef.name)}: ${result.description} - Next: ${chalk7.cyan(result.nextRun.toLocaleString())}`);
1624
1633
  const upcoming = getNextExecutions(cronExpression, 3, {
1625
1634
  timezone: jobDef.timezone ?? config.cron.defaultTimezone
1626
1635
  });
1627
- logger.info(`${chalk7.blue(" Upcoming:")} ${upcoming.map((d) => d.toLocaleTimeString()).join(", ")}`);
1636
+ logger.debug(`${chalk7.blue(" Upcoming:")} ${upcoming.map((d) => d.toLocaleTimeString()).join(", ")}`);
1628
1637
  }
1629
1638
  const job = {
1630
1639
  id: generateJobId(),
@@ -1688,19 +1697,19 @@ var createExecutionsData = (state) => ({
1688
1697
  running: Object.values(state.executions).filter((e) => e.status === "running")
1689
1698
  });
1690
1699
  var registerDashboardRoute = (app, state) => {
1691
- app.get("/dashboard", async function(_, reply) {
1700
+ app.get("/schedule/dashboard", async function(_, reply) {
1692
1701
  const dashboardData = createDashboardData(state);
1693
1702
  return reply.status(200).send(dashboardData);
1694
1703
  });
1695
1704
  };
1696
1705
  var registerExecutionsRoute = (app, state) => {
1697
- app.get("/executions", async function(_, reply) {
1706
+ app.get("/schedule/executions", async function(_, reply) {
1698
1707
  const executionsData = createExecutionsData(state);
1699
1708
  return reply.status(200).send(executionsData);
1700
1709
  });
1701
1710
  };
1702
1711
  var registerTriggerJobRoute = (app, state, executeJobFn) => {
1703
- app.post("/jobs/:jobId/trigger", async function(request, reply) {
1712
+ app.post("/schedule/jobs/:jobId/trigger", async function(request, reply) {
1704
1713
  const scheduler = state.schedulers[request.params.jobId];
1705
1714
  if (!scheduler) {
1706
1715
  return reply.status(404).send({ error: "Job not found" });
@@ -1713,7 +1722,7 @@ var registerTriggerJobRoute = (app, state, executeJobFn) => {
1713
1722
  });
1714
1723
  };
1715
1724
  var registerEnableJobRoute = (app, state, scheduleJobFn) => {
1716
- app.put("/jobs/:jobId/enable", async function(request, reply) {
1725
+ app.put("/schedule/jobs/:jobId/enable", async function(request, reply) {
1717
1726
  const scheduler = state.schedulers[request.params.jobId];
1718
1727
  if (!scheduler) {
1719
1728
  return reply.status(404).send({ error: "Job not found" });
@@ -1725,7 +1734,7 @@ var registerEnableJobRoute = (app, state, scheduleJobFn) => {
1725
1734
  });
1726
1735
  };
1727
1736
  var registerDisableJobRoute = (app, state) => {
1728
- app.put("/jobs/:jobId/disable", async function(request, reply) {
1737
+ app.put("/schedule/jobs/:jobId/disable", async function(request, reply) {
1729
1738
  const scheduler = state.schedulers[request.params.jobId];
1730
1739
  if (!scheduler) {
1731
1740
  return reply.status(404).send({ error: "Job not found" });
@@ -1839,7 +1848,7 @@ var createSchedulerManager = ({
1839
1848
  throw new Error(`Job '${jobName}' does not exist`);
1840
1849
  }
1841
1850
  if (scheduler.job.enabled) {
1842
- logger.info(`${logSymbols6.info} ${chalk8.blue("Job is already enabled:")} ${chalk8.magenta(jobName)}`);
1851
+ logger.debug(`${logSymbols6.info} ${chalk8.blue("Job is already enabled:")} ${chalk8.magenta(jobName)}`);
1843
1852
  return;
1844
1853
  }
1845
1854
  scheduler.job.enabled = true;
@@ -1858,7 +1867,7 @@ var createSchedulerManager = ({
1858
1867
  throw new Error(`Job '${jobName}' does not exist`);
1859
1868
  }
1860
1869
  if (!scheduler.job.enabled) {
1861
- logger.info(`${logSymbols6.info} ${chalk8.blue("Job is already disabled:")} ${chalk8.magenta(jobName)}`);
1870
+ logger.debug(`${logSymbols6.info} ${chalk8.blue("Job is already disabled:")} ${chalk8.magenta(jobName)}`);
1862
1871
  return;
1863
1872
  }
1864
1873
  scheduler.job.enabled = false;