@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.
- package/dist/dev-console-plugin/index.d.ts +0 -2
- package/dist/dev-console-plugin/index.js +133 -103
- package/dist/dev-console-plugin/index.js.map +1 -1
- package/dist/index.js +55 -7
- package/dist/index.js.map +1 -1
- package/dist/queue-plugin/index.d.ts +1 -2
- package/dist/queue-plugin/index.js +57 -33
- package/dist/queue-plugin/index.js.map +1 -1
- package/dist/schedule-plugin/index.d.ts +3 -1
- package/dist/schedule-plugin/index.js +53 -42
- 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
|
}
|
|
@@ -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.
|
|
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
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
(
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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 = (
|
|
1823
|
-
return Object.values(state.schedulers).filter((s) => !
|
|
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.
|
|
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.
|
|
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;
|