@cloudnux/local-cloud-provider 0.7.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.
- package/dist/dev-console-plugin/index.d.ts +0 -2
- package/dist/dev-console-plugin/index.js +82 -52
- package/dist/dev-console-plugin/index.js.map +1 -1
- package/dist/index.js +38 -1
- package/dist/index.js.map +1 -1
- package/dist/queue-plugin/index.d.ts +1 -2
- package/dist/queue-plugin/index.js +38 -17
- package/dist/queue-plugin/index.js.map +1 -1
- package/dist/schedule-plugin/index.d.ts +3 -1
- package/dist/schedule-plugin/index.js +44 -35
- package/dist/schedule-plugin/index.js.map +1 -1
- package/dist/websocket-plugin/index.d.ts +43 -0
- package/dist/websocket-plugin/index.js +96 -0
- package/dist/websocket-plugin/index.js.map +1 -0
- package/package.json +10 -3
|
@@ -81,7 +81,9 @@ interface SchedulerState {
|
|
|
81
81
|
executionHistory: JobExecution[];
|
|
82
82
|
isShuttingDown: boolean;
|
|
83
83
|
runningExecutions: number;
|
|
84
|
-
|
|
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.
|
|
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
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
(
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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;
|