@gravito/zenith 1.0.0-beta.1 → 1.0.1
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/CHANGELOG.md +15 -0
- package/dist/bin.js +436 -43
- package/dist/client/assets/index-C332gZ-J.css +1 -0
- package/dist/client/assets/{index-oXEse8ih.js → index-D4HibwTK.js} +88 -88
- package/dist/client/index.html +2 -2
- package/dist/server/index.js +436 -43
- package/docs/LARAVEL_ZENITH_ROADMAP.md +109 -0
- package/{QUASAR_MASTER_PLAN.md → docs/QUASAR_MASTER_PLAN.md} +6 -3
- package/package.json +1 -1
- package/scripts/debug_redis_keys.ts +24 -0
- package/src/client/App.tsx +1 -1
- package/src/client/Layout.tsx +11 -12
- package/src/client/WorkerStatus.tsx +97 -56
- package/src/client/components/BrandIcons.tsx +119 -44
- package/src/client/components/ConfirmDialog.tsx +0 -1
- package/src/client/components/JobInspector.tsx +18 -6
- package/src/client/components/PageHeader.tsx +32 -28
- package/src/client/pages/OverviewPage.tsx +0 -1
- package/src/client/pages/PulsePage.tsx +422 -340
- package/src/client/pages/SettingsPage.tsx +69 -15
- package/src/client/pages/WorkersPage.tsx +70 -2
- package/src/server/index.ts +171 -11
- package/src/server/services/QueueService.ts +6 -3
- package/src/shared/types.ts +2 -0
- package/ARCHITECTURE.md +0 -88
- package/BATCH_OPERATIONS_IMPLEMENTATION.md +0 -159
- package/EVOLUTION_BLUEPRINT.md +0 -112
- package/JOBINSPECTOR_SCROLL_FIX.md +0 -152
- package/TESTING_BATCH_OPERATIONS.md +0 -252
- package/dist/client/assets/index-BSTyMCFd.css +0 -1
- /package/{ALERTING_GUIDE.md → docs/ALERTING_GUIDE.md} +0 -0
- /package/{DEPLOYMENT.md → docs/DEPLOYMENT.md} +0 -0
- /package/{DOCS_INTERNAL.md → docs/DOCS_INTERNAL.md} +0 -0
- /package/{QUICK_TEST_GUIDE.md → docs/QUICK_TEST_GUIDE.md} +0 -0
- /package/{ROADMAP.md → docs/ROADMAP.md} +0 -0
package/dist/server/index.js
CHANGED
|
@@ -68748,19 +68748,19 @@ class Grammar {
|
|
|
68748
68748
|
return `INSERT INTO ${this.wrapTable(query.table)} (${columnList}) VALUES ${valuesList}`;
|
|
68749
68749
|
}
|
|
68750
68750
|
compileUpdate(query, values) {
|
|
68751
|
-
const columns = Object.keys(values);
|
|
68752
68751
|
let bindingIndex = 0;
|
|
68753
|
-
const setClause =
|
|
68752
|
+
const setClause = Object.entries(values).map(([col, value]) => {
|
|
68753
|
+
if (value instanceof Expression) {
|
|
68754
|
+
return `${this.wrapColumn(col)} = ${value.getValue()}`;
|
|
68755
|
+
}
|
|
68754
68756
|
const placeholder = this.getPlaceholder(bindingIndex);
|
|
68755
68757
|
bindingIndex++;
|
|
68756
68758
|
return `${this.wrapColumn(col)} = ${placeholder}`;
|
|
68757
68759
|
}).join(", ");
|
|
68758
68760
|
let sql = `UPDATE ${this.wrapTable(query.table)} SET ${setClause}`;
|
|
68759
68761
|
if (query.wheres.length > 0) {
|
|
68760
|
-
const
|
|
68761
|
-
|
|
68762
|
-
const wheres = this.compileWheres(offsetQuery);
|
|
68763
|
-
sql += ` ${this.offsetPlaceholders(wheres, whereBindingsOffset)}`;
|
|
68762
|
+
const wheres = this.compileWheres(query, bindingIndex);
|
|
68763
|
+
sql += ` ${wheres}`;
|
|
68764
68764
|
}
|
|
68765
68765
|
return sql;
|
|
68766
68766
|
}
|
|
@@ -70366,7 +70366,14 @@ class QueryBuilder {
|
|
|
70366
70366
|
return id;
|
|
70367
70367
|
}
|
|
70368
70368
|
async update(data) {
|
|
70369
|
-
const values =
|
|
70369
|
+
const values = [];
|
|
70370
|
+
for (const value of Object.values(data)) {
|
|
70371
|
+
if (value instanceof Expression) {
|
|
70372
|
+
values.push(...value.getBindings());
|
|
70373
|
+
} else {
|
|
70374
|
+
values.push(value);
|
|
70375
|
+
}
|
|
70376
|
+
}
|
|
70370
70377
|
const allBindings = [...values, ...this.bindingsList];
|
|
70371
70378
|
const compiled = this.getCompiledQuery();
|
|
70372
70379
|
compiled.bindings = allBindings;
|
|
@@ -71472,7 +71479,7 @@ var require_dist_cjs = __commonJS((exports) => {
|
|
|
71472
71479
|
|
|
71473
71480
|
// ../../node_modules/.bun/@smithy+protocol-http@5.3.7/node_modules/@smithy/protocol-http/dist-cjs/index.js
|
|
71474
71481
|
var require_dist_cjs2 = __commonJS((exports) => {
|
|
71475
|
-
var
|
|
71482
|
+
var types4 = require_dist_cjs();
|
|
71476
71483
|
var getHttpHandlerExtensionConfiguration = (runtimeConfig) => {
|
|
71477
71484
|
return {
|
|
71478
71485
|
setHttpHandler(handler) {
|
|
@@ -71499,7 +71506,7 @@ var require_dist_cjs2 = __commonJS((exports) => {
|
|
|
71499
71506
|
name;
|
|
71500
71507
|
kind;
|
|
71501
71508
|
values;
|
|
71502
|
-
constructor({ name, kind =
|
|
71509
|
+
constructor({ name, kind = types4.FieldPosition.HEADER, values = [] }) {
|
|
71503
71510
|
this.name = name;
|
|
71504
71511
|
this.kind = kind;
|
|
71505
71512
|
this.values = values;
|
|
@@ -73986,8 +73993,8 @@ var require_dist_cjs16 = __commonJS((exports) => {
|
|
|
73986
73993
|
|
|
73987
73994
|
// ../../node_modules/.bun/@smithy+util-middleware@4.2.7/node_modules/@smithy/util-middleware/dist-cjs/index.js
|
|
73988
73995
|
var require_dist_cjs17 = __commonJS((exports) => {
|
|
73989
|
-
var
|
|
73990
|
-
var getSmithyContext = (context) => context[
|
|
73996
|
+
var types4 = require_dist_cjs();
|
|
73997
|
+
var getSmithyContext = (context) => context[types4.SMITHY_CONTEXT_KEY] || (context[types4.SMITHY_CONTEXT_KEY] = {});
|
|
73991
73998
|
var normalizeProvider = (input) => {
|
|
73992
73999
|
if (typeof input === "function")
|
|
73993
74000
|
return input;
|
|
@@ -76932,7 +76939,7 @@ var require_protocols = __commonJS((exports) => {
|
|
|
76932
76939
|
var require_dist_cjs19 = __commonJS((exports) => {
|
|
76933
76940
|
var middlewareStack = require_dist_cjs6();
|
|
76934
76941
|
var protocols = require_protocols();
|
|
76935
|
-
var
|
|
76942
|
+
var types4 = require_dist_cjs();
|
|
76936
76943
|
var schema2 = require_schema();
|
|
76937
76944
|
var serde = require_serde();
|
|
76938
76945
|
|
|
@@ -77031,7 +77038,7 @@ var require_dist_cjs19 = __commonJS((exports) => {
|
|
|
77031
77038
|
commandName,
|
|
77032
77039
|
inputFilterSensitiveLog,
|
|
77033
77040
|
outputFilterSensitiveLog,
|
|
77034
|
-
[
|
|
77041
|
+
[types4.SMITHY_CONTEXT_KEY]: {
|
|
77035
77042
|
commandInstance: this,
|
|
77036
77043
|
...smithyContext
|
|
77037
77044
|
},
|
|
@@ -77256,8 +77263,8 @@ var require_dist_cjs19 = __commonJS((exports) => {
|
|
|
77256
77263
|
};
|
|
77257
77264
|
var getChecksumConfiguration = (runtimeConfig) => {
|
|
77258
77265
|
const checksumAlgorithms = [];
|
|
77259
|
-
for (const id in
|
|
77260
|
-
const algorithmId =
|
|
77266
|
+
for (const id in types4.AlgorithmId) {
|
|
77267
|
+
const algorithmId = types4.AlgorithmId[id];
|
|
77261
77268
|
if (runtimeConfig[algorithmId] === undefined) {
|
|
77262
77269
|
continue;
|
|
77263
77270
|
}
|
|
@@ -77765,12 +77772,12 @@ var require_dist_cjs20 = __commonJS((exports) => {
|
|
|
77765
77772
|
|
|
77766
77773
|
// ../../node_modules/.bun/@smithy+core@3.20.0/node_modules/@smithy/core/dist-cjs/index.js
|
|
77767
77774
|
var require_dist_cjs21 = __commonJS((exports) => {
|
|
77768
|
-
var
|
|
77775
|
+
var types4 = require_dist_cjs();
|
|
77769
77776
|
var utilMiddleware = require_dist_cjs17();
|
|
77770
77777
|
var middlewareSerde = require_dist_cjs20();
|
|
77771
77778
|
var protocolHttp = require_dist_cjs2();
|
|
77772
77779
|
var protocols = require_protocols();
|
|
77773
|
-
var getSmithyContext = (context) => context[
|
|
77780
|
+
var getSmithyContext = (context) => context[types4.SMITHY_CONTEXT_KEY] || (context[types4.SMITHY_CONTEXT_KEY] = {});
|
|
77774
77781
|
var resolveAuthOptions = (candidateAuthOptions, authSchemePreference) => {
|
|
77775
77782
|
if (!authSchemePreference || authSchemePreference.length === 0) {
|
|
77776
77783
|
return candidateAuthOptions;
|
|
@@ -77985,9 +77992,9 @@ var require_dist_cjs21 = __commonJS((exports) => {
|
|
|
77985
77992
|
throw new Error("request could not be signed with `apiKey` since the `apiKey` is not defined");
|
|
77986
77993
|
}
|
|
77987
77994
|
const clonedRequest = protocolHttp.HttpRequest.clone(httpRequest);
|
|
77988
|
-
if (signingProperties.in ===
|
|
77995
|
+
if (signingProperties.in === types4.HttpApiKeyAuthLocation.QUERY) {
|
|
77989
77996
|
clonedRequest.query[signingProperties.name] = identity.apiKey;
|
|
77990
|
-
} else if (signingProperties.in ===
|
|
77997
|
+
} else if (signingProperties.in === types4.HttpApiKeyAuthLocation.HEADER) {
|
|
77991
77998
|
clonedRequest.headers[signingProperties.name] = signingProperties.scheme ? `${signingProperties.scheme} ${identity.apiKey}` : identity.apiKey;
|
|
77992
77999
|
} else {
|
|
77993
78000
|
throw new Error("request can only be signed with `apiKey` locations `query` or `header`, " + "but found: `" + signingProperties.in + "`");
|
|
@@ -78097,7 +78104,7 @@ var require_dist_cjs21 = __commonJS((exports) => {
|
|
|
78097
78104
|
|
|
78098
78105
|
// ../../node_modules/.bun/@smithy+util-endpoints@3.2.7/node_modules/@smithy/util-endpoints/dist-cjs/index.js
|
|
78099
78106
|
var require_dist_cjs22 = __commonJS((exports) => {
|
|
78100
|
-
var
|
|
78107
|
+
var types4 = require_dist_cjs();
|
|
78101
78108
|
|
|
78102
78109
|
class EndpointCache {
|
|
78103
78110
|
capacity;
|
|
@@ -78220,8 +78227,8 @@ var require_dist_cjs22 = __commonJS((exports) => {
|
|
|
78220
78227
|
var isSet = (value) => value != null;
|
|
78221
78228
|
var not = (value) => !value;
|
|
78222
78229
|
var DEFAULT_PORTS = {
|
|
78223
|
-
[
|
|
78224
|
-
[
|
|
78230
|
+
[types4.EndpointURLScheme.HTTP]: 80,
|
|
78231
|
+
[types4.EndpointURLScheme.HTTPS]: 443
|
|
78225
78232
|
};
|
|
78226
78233
|
var parseURL = (value) => {
|
|
78227
78234
|
const whatwgURL = (() => {
|
|
@@ -78250,7 +78257,7 @@ var require_dist_cjs22 = __commonJS((exports) => {
|
|
|
78250
78257
|
return null;
|
|
78251
78258
|
}
|
|
78252
78259
|
const scheme = protocol.slice(0, -1);
|
|
78253
|
-
if (!Object.values(
|
|
78260
|
+
if (!Object.values(types4.EndpointURLScheme).includes(scheme)) {
|
|
78254
78261
|
return null;
|
|
78255
78262
|
}
|
|
78256
78263
|
const isIp = isIpAddress(hostname);
|
|
@@ -84380,7 +84387,7 @@ var require_dist_cjs35 = __commonJS((exports) => {
|
|
|
84380
84387
|
var getSSOTokenFilepath = require_getSSOTokenFilepath();
|
|
84381
84388
|
var getSSOTokenFromFile = require_getSSOTokenFromFile();
|
|
84382
84389
|
var path = __require("path");
|
|
84383
|
-
var
|
|
84390
|
+
var types4 = require_dist_cjs();
|
|
84384
84391
|
var readFile = require_readFile();
|
|
84385
84392
|
var ENV_PROFILE = "AWS_PROFILE";
|
|
84386
84393
|
var DEFAULT_PROFILE = "default";
|
|
@@ -84391,10 +84398,10 @@ var require_dist_cjs35 = __commonJS((exports) => {
|
|
|
84391
84398
|
if (indexOfSeparator === -1) {
|
|
84392
84399
|
return false;
|
|
84393
84400
|
}
|
|
84394
|
-
return Object.values(
|
|
84401
|
+
return Object.values(types4.IniSectionType).includes(key.substring(0, indexOfSeparator));
|
|
84395
84402
|
}).reduce((acc, [key, value]) => {
|
|
84396
84403
|
const indexOfSeparator = key.indexOf(CONFIG_PREFIX_SEPARATOR);
|
|
84397
|
-
const updatedKey = key.substring(0, indexOfSeparator) ===
|
|
84404
|
+
const updatedKey = key.substring(0, indexOfSeparator) === types4.IniSectionType.PROFILE ? key.substring(indexOfSeparator + 1) : key;
|
|
84398
84405
|
acc[updatedKey] = value;
|
|
84399
84406
|
return acc;
|
|
84400
84407
|
}, {
|
|
@@ -84420,7 +84427,7 @@ var require_dist_cjs35 = __commonJS((exports) => {
|
|
|
84420
84427
|
const matches = prefixKeyRegex.exec(sectionName);
|
|
84421
84428
|
if (matches) {
|
|
84422
84429
|
const [, prefix, , name] = matches;
|
|
84423
|
-
if (Object.values(
|
|
84430
|
+
if (Object.values(types4.IniSectionType).includes(prefix)) {
|
|
84424
84431
|
currentSection = [prefix, name].join(CONFIG_PREFIX_SEPARATOR);
|
|
84425
84432
|
}
|
|
84426
84433
|
} else {
|
|
@@ -84477,7 +84484,7 @@ var require_dist_cjs35 = __commonJS((exports) => {
|
|
|
84477
84484
|
credentialsFile: parsedFiles[1]
|
|
84478
84485
|
};
|
|
84479
84486
|
};
|
|
84480
|
-
var getSsoSessionData = (data) => Object.entries(data).filter(([key]) => key.startsWith(
|
|
84487
|
+
var getSsoSessionData = (data) => Object.entries(data).filter(([key]) => key.startsWith(types4.IniSectionType.SSO_SESSION + CONFIG_PREFIX_SEPARATOR)).reduce((acc, [key, value]) => ({ ...acc, [key.substring(key.indexOf(CONFIG_PREFIX_SEPARATOR) + 1)]: value }), {});
|
|
84481
84488
|
var swallowError = () => ({});
|
|
84482
84489
|
var loadSsoSessionData = async (init = {}) => readFile.readFile(init.configFilepath ?? getConfigFilepath()).then(parseIni).then(getSsoSessionData).catch(swallowError);
|
|
84483
84490
|
var mergeConfigFiles = (...files) => {
|
|
@@ -113210,6 +113217,8 @@ class Migrator {
|
|
|
113210
113217
|
return MigrationClass;
|
|
113211
113218
|
}
|
|
113212
113219
|
}
|
|
113220
|
+
// ../atlas/src/OrbitAtlas.ts
|
|
113221
|
+
init_DB();
|
|
113213
113222
|
// ../atlas/src/orm/model/DirtyTracker.ts
|
|
113214
113223
|
class DirtyTracker {
|
|
113215
113224
|
original = new Map;
|
|
@@ -115484,6 +115493,155 @@ var Hono2 = class extends Hono {
|
|
|
115484
115493
|
}
|
|
115485
115494
|
};
|
|
115486
115495
|
|
|
115496
|
+
// ../quasar/src/bridges/BaseZenithBridge.ts
|
|
115497
|
+
class BaseZenithBridge {
|
|
115498
|
+
redis;
|
|
115499
|
+
prefix;
|
|
115500
|
+
workerId;
|
|
115501
|
+
listeners = [];
|
|
115502
|
+
constructor(redis, prefix = "flux_console:", workerId) {
|
|
115503
|
+
this.redis = redis;
|
|
115504
|
+
this.prefix = prefix;
|
|
115505
|
+
this.workerId = workerId;
|
|
115506
|
+
}
|
|
115507
|
+
async publishLog(payload) {
|
|
115508
|
+
try {
|
|
115509
|
+
const fullPayload = {
|
|
115510
|
+
...payload,
|
|
115511
|
+
workerId: payload.workerId || this.workerId,
|
|
115512
|
+
timestamp: payload.timestamp || new Date().toISOString()
|
|
115513
|
+
};
|
|
115514
|
+
await this.redis.publish(`${this.prefix}logs`, JSON.stringify(fullPayload));
|
|
115515
|
+
const historyKey = `${this.prefix}logs:history`;
|
|
115516
|
+
if (typeof this.redis.pipeline === "function") {
|
|
115517
|
+
const pipe = this.redis.pipeline();
|
|
115518
|
+
pipe.lpush(historyKey, JSON.stringify(fullPayload));
|
|
115519
|
+
pipe.ltrim(historyKey, 0, 99);
|
|
115520
|
+
await pipe.exec();
|
|
115521
|
+
} else {
|
|
115522
|
+
await this.redis.lpush(historyKey, JSON.stringify(fullPayload));
|
|
115523
|
+
}
|
|
115524
|
+
} catch (err) {
|
|
115525
|
+
console.error("[BaseZenithBridge] Failed to publish log:", err);
|
|
115526
|
+
}
|
|
115527
|
+
}
|
|
115528
|
+
registerListener(target, event, handler) {
|
|
115529
|
+
this.listeners.push({ target, event, handler });
|
|
115530
|
+
}
|
|
115531
|
+
detach() {
|
|
115532
|
+
for (const { target, event, handler } of this.listeners) {
|
|
115533
|
+
if (typeof target.off === "function") {
|
|
115534
|
+
target.off(event, handler);
|
|
115535
|
+
} else if (typeof target.removeListener === "function") {
|
|
115536
|
+
target.removeListener(event, handler);
|
|
115537
|
+
}
|
|
115538
|
+
}
|
|
115539
|
+
this.listeners = [];
|
|
115540
|
+
}
|
|
115541
|
+
}
|
|
115542
|
+
// ../quasar/src/bridges/BeeQueueBridge.ts
|
|
115543
|
+
class BeeQueueBridge extends BaseZenithBridge {
|
|
115544
|
+
attach(queue) {
|
|
115545
|
+
const onSucceeded = async (job, result) => {
|
|
115546
|
+
await this.publishLog({
|
|
115547
|
+
level: "success",
|
|
115548
|
+
message: `Completed job: ${job.id}`,
|
|
115549
|
+
jobId: job.id,
|
|
115550
|
+
context: {
|
|
115551
|
+
data: job.data,
|
|
115552
|
+
result: typeof result === "object" ? JSON.stringify(result) : result
|
|
115553
|
+
}
|
|
115554
|
+
});
|
|
115555
|
+
};
|
|
115556
|
+
const onFailed = async (job, error) => {
|
|
115557
|
+
await this.publishLog({
|
|
115558
|
+
level: "error",
|
|
115559
|
+
message: `Job failed: ${job.id} - ${error.message}`,
|
|
115560
|
+
jobId: job.id,
|
|
115561
|
+
context: {
|
|
115562
|
+
data: job.data,
|
|
115563
|
+
error: error.message,
|
|
115564
|
+
stack: error.stack
|
|
115565
|
+
}
|
|
115566
|
+
});
|
|
115567
|
+
};
|
|
115568
|
+
const onProgress = async (job, progress) => {
|
|
115569
|
+
await this.publishLog({
|
|
115570
|
+
level: "info",
|
|
115571
|
+
message: `Job progress: ${job.id}`,
|
|
115572
|
+
jobId: job.id,
|
|
115573
|
+
context: {
|
|
115574
|
+
data: job.data,
|
|
115575
|
+
progress
|
|
115576
|
+
}
|
|
115577
|
+
});
|
|
115578
|
+
};
|
|
115579
|
+
queue.on("job succeeded", onSucceeded);
|
|
115580
|
+
queue.on("job failed", onFailed);
|
|
115581
|
+
queue.on("job progress", onProgress);
|
|
115582
|
+
this.registerListener(queue, "job succeeded", onSucceeded);
|
|
115583
|
+
this.registerListener(queue, "job failed", onFailed);
|
|
115584
|
+
this.registerListener(queue, "job progress", onProgress);
|
|
115585
|
+
}
|
|
115586
|
+
}
|
|
115587
|
+
// ../quasar/src/bridges/BullMQBridge.ts
|
|
115588
|
+
class BullMQBridge extends BaseZenithBridge {
|
|
115589
|
+
attach(worker) {
|
|
115590
|
+
const onActive = async (job) => {
|
|
115591
|
+
await this.publishLog({
|
|
115592
|
+
level: "info",
|
|
115593
|
+
message: `Processing job: ${job.name || job.id}`,
|
|
115594
|
+
jobId: job.id,
|
|
115595
|
+
context: {
|
|
115596
|
+
name: job.name,
|
|
115597
|
+
data: job.data
|
|
115598
|
+
}
|
|
115599
|
+
});
|
|
115600
|
+
};
|
|
115601
|
+
const onCompleted = async (job, result) => {
|
|
115602
|
+
await this.publishLog({
|
|
115603
|
+
level: "success",
|
|
115604
|
+
message: `Completed job: ${job.name || job.id}`,
|
|
115605
|
+
jobId: job.id,
|
|
115606
|
+
context: {
|
|
115607
|
+
name: job.name,
|
|
115608
|
+
result: typeof result === "object" ? JSON.stringify(result) : result
|
|
115609
|
+
}
|
|
115610
|
+
});
|
|
115611
|
+
};
|
|
115612
|
+
const onFailed = async (job, error) => {
|
|
115613
|
+
await this.publishLog({
|
|
115614
|
+
level: "error",
|
|
115615
|
+
message: `Job failed: ${job?.name || job?.id} - ${error.message}`,
|
|
115616
|
+
jobId: job?.id,
|
|
115617
|
+
context: {
|
|
115618
|
+
name: job?.name,
|
|
115619
|
+
error: error.message,
|
|
115620
|
+
stack: error.stack
|
|
115621
|
+
}
|
|
115622
|
+
});
|
|
115623
|
+
};
|
|
115624
|
+
const onProgress = async (job, progress) => {
|
|
115625
|
+
await this.publishLog({
|
|
115626
|
+
level: "info",
|
|
115627
|
+
message: `Job progress: ${job.name || job.id}`,
|
|
115628
|
+
jobId: job.id,
|
|
115629
|
+
context: {
|
|
115630
|
+
name: job.name,
|
|
115631
|
+
progress
|
|
115632
|
+
}
|
|
115633
|
+
});
|
|
115634
|
+
};
|
|
115635
|
+
worker.on("active", onActive);
|
|
115636
|
+
worker.on("completed", onCompleted);
|
|
115637
|
+
worker.on("failed", onFailed);
|
|
115638
|
+
worker.on("progress", onProgress);
|
|
115639
|
+
this.registerListener(worker, "active", onActive);
|
|
115640
|
+
this.registerListener(worker, "completed", onCompleted);
|
|
115641
|
+
this.registerListener(worker, "failed", onFailed);
|
|
115642
|
+
this.registerListener(worker, "progress", onProgress);
|
|
115643
|
+
}
|
|
115644
|
+
}
|
|
115487
115645
|
// ../quasar/src/executors/BaseExecutor.ts
|
|
115488
115646
|
class BaseExecutor {
|
|
115489
115647
|
success(commandId, message) {
|
|
@@ -115723,6 +115881,76 @@ class CommandListener {
|
|
|
115723
115881
|
}
|
|
115724
115882
|
}
|
|
115725
115883
|
}
|
|
115884
|
+
// ../quasar/src/probes/BeeQueueProbe.ts
|
|
115885
|
+
class BeeQueueProbe {
|
|
115886
|
+
redis;
|
|
115887
|
+
queueName;
|
|
115888
|
+
prefix;
|
|
115889
|
+
constructor(redis, queueName, prefix = "bq") {
|
|
115890
|
+
this.redis = redis;
|
|
115891
|
+
this.queueName = queueName;
|
|
115892
|
+
this.prefix = prefix;
|
|
115893
|
+
}
|
|
115894
|
+
async getSnapshot() {
|
|
115895
|
+
const key = (suffix) => `${this.prefix}:${this.queueName}:${suffix}`;
|
|
115896
|
+
const pipeline = this.redis.pipeline();
|
|
115897
|
+
pipeline.llen(key("waiting"));
|
|
115898
|
+
pipeline.llen(key("active"));
|
|
115899
|
+
pipeline.llen(key("failed"));
|
|
115900
|
+
const results = await pipeline.exec();
|
|
115901
|
+
if (!results)
|
|
115902
|
+
throw new Error("Redis pipeline failed");
|
|
115903
|
+
const [_waitingErr, waiting] = results[0];
|
|
115904
|
+
const [_activeErr, active] = results[1];
|
|
115905
|
+
const [_failedErr, failed] = results[2];
|
|
115906
|
+
return {
|
|
115907
|
+
name: this.queueName,
|
|
115908
|
+
driver: "redis",
|
|
115909
|
+
size: {
|
|
115910
|
+
waiting: Number(waiting || 0),
|
|
115911
|
+
active: Number(active || 0),
|
|
115912
|
+
failed: Number(failed || 0),
|
|
115913
|
+
delayed: 0
|
|
115914
|
+
}
|
|
115915
|
+
};
|
|
115916
|
+
}
|
|
115917
|
+
}
|
|
115918
|
+
// ../quasar/src/probes/BullMQProbe.ts
|
|
115919
|
+
class BullMQProbe {
|
|
115920
|
+
redis;
|
|
115921
|
+
queueName;
|
|
115922
|
+
prefix;
|
|
115923
|
+
constructor(redis, queueName, prefix = "bull") {
|
|
115924
|
+
this.redis = redis;
|
|
115925
|
+
this.queueName = queueName;
|
|
115926
|
+
this.prefix = prefix;
|
|
115927
|
+
}
|
|
115928
|
+
async getSnapshot() {
|
|
115929
|
+
const key = (suffix) => `${this.prefix}:${this.queueName}:${suffix}`;
|
|
115930
|
+
const pipeline = this.redis.pipeline();
|
|
115931
|
+
pipeline.llen(key("wait"));
|
|
115932
|
+
pipeline.llen(key("active"));
|
|
115933
|
+
pipeline.zcard(key("delayed"));
|
|
115934
|
+
pipeline.scard(key("failed"));
|
|
115935
|
+
const results = await pipeline.exec();
|
|
115936
|
+
if (!results)
|
|
115937
|
+
throw new Error("Redis pipeline failed");
|
|
115938
|
+
const [_waitErr, waiting] = results[0];
|
|
115939
|
+
const [_activeErr, active] = results[1];
|
|
115940
|
+
const [_delayedErr, delayed] = results[2];
|
|
115941
|
+
const [_failedErr, failed] = results[3];
|
|
115942
|
+
return {
|
|
115943
|
+
name: this.queueName,
|
|
115944
|
+
driver: "redis",
|
|
115945
|
+
size: {
|
|
115946
|
+
waiting: Number(waiting || 0),
|
|
115947
|
+
active: Number(active || 0),
|
|
115948
|
+
failed: Number(failed || 0),
|
|
115949
|
+
delayed: Number(delayed || 0)
|
|
115950
|
+
}
|
|
115951
|
+
};
|
|
115952
|
+
}
|
|
115953
|
+
}
|
|
115726
115954
|
// ../quasar/src/probes/NodeProbe.ts
|
|
115727
115955
|
import os from "os";
|
|
115728
115956
|
import process2 from "process";
|
|
@@ -115821,10 +116049,10 @@ class BullProbe {
|
|
|
115821
116049
|
const results = await pipeline.exec();
|
|
115822
116050
|
if (!results)
|
|
115823
116051
|
throw new Error("Redis pipeline failed");
|
|
115824
|
-
const [
|
|
115825
|
-
const [
|
|
115826
|
-
const [
|
|
115827
|
-
const [
|
|
116052
|
+
const [_waitingErr, waiting] = results[0];
|
|
116053
|
+
const [_activeErr, active] = results[1];
|
|
116054
|
+
const [_delayedErr, delayed] = results[2];
|
|
116055
|
+
const [_failedErr, failed] = results[3];
|
|
115828
116056
|
return {
|
|
115829
116057
|
name: this.queueName,
|
|
115830
116058
|
driver: "redis",
|
|
@@ -115907,6 +116135,7 @@ class QuasarAgent {
|
|
|
115907
116135
|
interval;
|
|
115908
116136
|
probe;
|
|
115909
116137
|
queueProbes = [];
|
|
116138
|
+
bridges = [];
|
|
115910
116139
|
timer = null;
|
|
115911
116140
|
prefix = "gravito:quasar:node:";
|
|
115912
116141
|
nodeId;
|
|
@@ -115983,7 +116212,30 @@ class QuasarAgent {
|
|
|
115983
116212
|
this.queueProbes.push(new LaravelProbe(this.monitorRedis, name));
|
|
115984
116213
|
} else if (type === "bull") {
|
|
115985
116214
|
this.queueProbes.push(new BullProbe(this.monitorRedis, name));
|
|
116215
|
+
} else if (type === "bullmq") {
|
|
116216
|
+
this.queueProbes.push(new BullMQProbe(this.monitorRedis, name));
|
|
116217
|
+
} else if (type === "bee-queue") {
|
|
116218
|
+
this.queueProbes.push(new BeeQueueProbe(this.monitorRedis, name));
|
|
116219
|
+
}
|
|
116220
|
+
}
|
|
116221
|
+
attachBridge(worker, type) {
|
|
116222
|
+
if (!this.transportRedis) {
|
|
116223
|
+
console.warn("[Quasar] Cannot attach bridge: transport connection required");
|
|
116224
|
+
return;
|
|
115986
116225
|
}
|
|
116226
|
+
const workerId = this.nodeId || `${this.service}-${process.pid}`;
|
|
116227
|
+
let bridge;
|
|
116228
|
+
if (type === "bullmq") {
|
|
116229
|
+
bridge = new BullMQBridge(this.transportRedis, "flux_console:", workerId);
|
|
116230
|
+
} else if (type === "bee-queue") {
|
|
116231
|
+
bridge = new BeeQueueBridge(this.transportRedis, "flux_console:", workerId);
|
|
116232
|
+
} else {
|
|
116233
|
+
console.warn(`[Quasar] Unknown bridge type: ${type}`);
|
|
116234
|
+
return;
|
|
116235
|
+
}
|
|
116236
|
+
bridge.attach(worker);
|
|
116237
|
+
this.bridges.push(bridge);
|
|
116238
|
+
console.log(`[Quasar] \uD83D\uDD17 Attached ${type} bridge to worker`);
|
|
115987
116239
|
}
|
|
115988
116240
|
async enableRemoteControl() {
|
|
115989
116241
|
if (!this.monitorRedis) {
|
|
@@ -118485,7 +118737,7 @@ class QueueService {
|
|
|
118485
118737
|
return jobs;
|
|
118486
118738
|
}
|
|
118487
118739
|
}
|
|
118488
|
-
async recordStatusMetrics(nodes = {}) {
|
|
118740
|
+
async recordStatusMetrics(nodes = {}, injectedWorkers) {
|
|
118489
118741
|
const stats = await this.listQueues();
|
|
118490
118742
|
const totals = stats.reduce((acc, q3) => {
|
|
118491
118743
|
acc.waiting += q3.waiting;
|
|
@@ -118498,7 +118750,7 @@ class QueueService {
|
|
|
118498
118750
|
pipe.set(`flux_console:metrics:waiting:${now}`, totals.waiting, "EX", 3600);
|
|
118499
118751
|
pipe.set(`flux_console:metrics:delayed:${now}`, totals.delayed, "EX", 3600);
|
|
118500
118752
|
pipe.set(`flux_console:metrics:failed:${now}`, totals.failed, "EX", 3600);
|
|
118501
|
-
const workers = await this.listWorkers();
|
|
118753
|
+
const workers = injectedWorkers || await this.listWorkers();
|
|
118502
118754
|
pipe.set(`flux_console:metrics:workers:${now}`, workers.length, "EX", 3600);
|
|
118503
118755
|
await pipe.exec();
|
|
118504
118756
|
this.logEmitter.emit("stats", {
|
|
@@ -118687,8 +118939,8 @@ class QueueService {
|
|
|
118687
118939
|
if (results.length >= limit) {
|
|
118688
118940
|
break;
|
|
118689
118941
|
}
|
|
118690
|
-
const
|
|
118691
|
-
for (const jobType of
|
|
118942
|
+
const types7 = type === "all" ? ["waiting", "delayed", "failed"] : [type];
|
|
118943
|
+
for (const jobType of types7) {
|
|
118692
118944
|
if (results.length >= limit) {
|
|
118693
118945
|
break;
|
|
118694
118946
|
}
|
|
@@ -118830,14 +119082,85 @@ queueService.connect().then(() => pulseService.connect()).then(() => commandServ
|
|
|
118830
119082
|
});
|
|
118831
119083
|
agent.start().catch((err) => console.error("[FluxConsole] Quasar Agent Error:", err));
|
|
118832
119084
|
console.log(`[FluxConsole] Connected to Redis at ${REDIS_URL}`);
|
|
118833
|
-
|
|
118834
|
-
|
|
118835
|
-
|
|
118836
|
-
|
|
119085
|
+
const updateMetrics = async () => {
|
|
119086
|
+
try {
|
|
119087
|
+
const [pulseNodes, legacyWorkers] = await Promise.all([
|
|
119088
|
+
pulseService.getNodes(),
|
|
119089
|
+
queueService.listWorkers()
|
|
119090
|
+
]);
|
|
119091
|
+
const pulseWorkers = Object.values(pulseNodes).flat().flatMap((node) => {
|
|
119092
|
+
const mainNode = {
|
|
119093
|
+
id: node.id,
|
|
119094
|
+
service: node.service,
|
|
119095
|
+
status: node.runtime.status || "online",
|
|
119096
|
+
pid: node.pid,
|
|
119097
|
+
uptime: node.runtime.uptime,
|
|
119098
|
+
metrics: {
|
|
119099
|
+
cpu: node.cpu.process,
|
|
119100
|
+
cores: node.cpu.cores,
|
|
119101
|
+
ram: {
|
|
119102
|
+
rss: node.memory.process.rss,
|
|
119103
|
+
heapUsed: node.memory.process.heapUsed,
|
|
119104
|
+
total: node.memory.system.total
|
|
119105
|
+
}
|
|
119106
|
+
},
|
|
119107
|
+
queues: node.queues,
|
|
119108
|
+
meta: node.meta
|
|
119109
|
+
};
|
|
119110
|
+
const subWorkers = [];
|
|
119111
|
+
if (node.meta?.laravel?.workers && Array.isArray(node.meta.laravel.workers)) {
|
|
119112
|
+
node.meta.laravel.workers.forEach((w3) => {
|
|
119113
|
+
subWorkers.push({
|
|
119114
|
+
id: `${node.id}-php-${w3.pid}`,
|
|
119115
|
+
service: `${node.service} / LARAVEL`,
|
|
119116
|
+
status: w3.status === "running" || w3.status === "sleep" ? "online" : "idle",
|
|
119117
|
+
pid: w3.pid,
|
|
119118
|
+
uptime: node.runtime.uptime,
|
|
119119
|
+
metrics: {
|
|
119120
|
+
cpu: w3.cpu,
|
|
119121
|
+
cores: 1,
|
|
119122
|
+
ram: {
|
|
119123
|
+
rss: w3.memory,
|
|
119124
|
+
heapUsed: w3.memory,
|
|
119125
|
+
total: node.memory.system.total
|
|
119126
|
+
}
|
|
119127
|
+
},
|
|
119128
|
+
meta: { isVirtual: true, cmdline: w3.cmdline }
|
|
119129
|
+
});
|
|
119130
|
+
});
|
|
119131
|
+
}
|
|
119132
|
+
return [mainNode, ...subWorkers];
|
|
119133
|
+
});
|
|
119134
|
+
const formattedLegacy = legacyWorkers.map((w3) => ({
|
|
119135
|
+
id: w3.id,
|
|
119136
|
+
status: "online",
|
|
119137
|
+
pid: w3.pid,
|
|
119138
|
+
uptime: w3.uptime,
|
|
119139
|
+
metrics: {
|
|
119140
|
+
cpu: (w3.loadAvg[0] || 0) * 100,
|
|
119141
|
+
cores: 0,
|
|
119142
|
+
ram: {
|
|
119143
|
+
rss: parseInt(w3.memory.rss || "0", 10),
|
|
119144
|
+
heapUsed: parseInt(w3.memory.heapUsed || "0", 10),
|
|
119145
|
+
total: 0
|
|
119146
|
+
}
|
|
119147
|
+
},
|
|
119148
|
+
queues: w3.queues.map((q3) => ({
|
|
119149
|
+
name: q3,
|
|
119150
|
+
size: { waiting: 0, active: 0, failed: 0, delayed: 0 }
|
|
119151
|
+
})),
|
|
119152
|
+
meta: {}
|
|
119153
|
+
}));
|
|
119154
|
+
await queueService.recordStatusMetrics(pulseNodes, [...pulseWorkers, ...formattedLegacy]);
|
|
119155
|
+
} catch (err) {
|
|
119156
|
+
console.error("[FluxConsole] Metrics Update Error:", err);
|
|
119157
|
+
}
|
|
119158
|
+
};
|
|
119159
|
+
setInterval(updateMetrics, 2000);
|
|
118837
119160
|
setInterval(() => {
|
|
118838
119161
|
queueService.tickScheduler().catch(console.error);
|
|
118839
119162
|
}, 5000);
|
|
118840
|
-
|
|
119163
|
+
updateMetrics();
|
|
118841
119164
|
}).catch((err) => {
|
|
118842
119165
|
console.error("[FluxConsole] Failed to connect to Redis", err);
|
|
118843
119166
|
});
|
|
@@ -119031,9 +119354,79 @@ api.get("/throughput", async (c3) => {
|
|
|
119031
119354
|
});
|
|
119032
119355
|
api.get("/workers", async (c3) => {
|
|
119033
119356
|
try {
|
|
119034
|
-
const
|
|
119035
|
-
|
|
119357
|
+
const [legacyWorkers, pulseNodes] = await Promise.all([
|
|
119358
|
+
queueService.listWorkers(),
|
|
119359
|
+
pulseService.getNodes()
|
|
119360
|
+
]);
|
|
119361
|
+
const pulseWorkers = Object.values(pulseNodes).flat().flatMap((node) => {
|
|
119362
|
+
const mainNode = {
|
|
119363
|
+
id: node.id,
|
|
119364
|
+
service: node.service,
|
|
119365
|
+
status: node.runtime.status || "online",
|
|
119366
|
+
pid: node.pid,
|
|
119367
|
+
uptime: node.runtime.uptime,
|
|
119368
|
+
metrics: {
|
|
119369
|
+
cpu: node.cpu.process,
|
|
119370
|
+
cores: node.cpu.cores,
|
|
119371
|
+
ram: {
|
|
119372
|
+
rss: node.memory.process.rss,
|
|
119373
|
+
heapUsed: node.memory.process.heapUsed,
|
|
119374
|
+
total: node.memory.system.total
|
|
119375
|
+
}
|
|
119376
|
+
},
|
|
119377
|
+
queues: node.queues,
|
|
119378
|
+
meta: node.meta
|
|
119379
|
+
};
|
|
119380
|
+
const subWorkers = [];
|
|
119381
|
+
if (node.meta?.laravel?.workers && Array.isArray(node.meta.laravel.workers)) {
|
|
119382
|
+
node.meta.laravel.workers.forEach((w3) => {
|
|
119383
|
+
subWorkers.push({
|
|
119384
|
+
id: `${node.id}-php-${w3.pid}`,
|
|
119385
|
+
service: `${node.service} / LARAVEL`,
|
|
119386
|
+
status: w3.status === "running" || w3.status === "sleep" ? "online" : "idle",
|
|
119387
|
+
pid: w3.pid,
|
|
119388
|
+
uptime: node.runtime.uptime,
|
|
119389
|
+
metrics: {
|
|
119390
|
+
cpu: w3.cpu,
|
|
119391
|
+
cores: 1,
|
|
119392
|
+
ram: {
|
|
119393
|
+
rss: w3.memory,
|
|
119394
|
+
heapUsed: w3.memory,
|
|
119395
|
+
total: node.memory.system.total
|
|
119396
|
+
}
|
|
119397
|
+
},
|
|
119398
|
+
meta: {
|
|
119399
|
+
isVirtual: true,
|
|
119400
|
+
cmdline: w3.cmdline
|
|
119401
|
+
}
|
|
119402
|
+
});
|
|
119403
|
+
});
|
|
119404
|
+
}
|
|
119405
|
+
return [mainNode, ...subWorkers];
|
|
119406
|
+
});
|
|
119407
|
+
const formattedLegacy = legacyWorkers.map((w3) => ({
|
|
119408
|
+
id: w3.id,
|
|
119409
|
+
status: "online",
|
|
119410
|
+
pid: w3.pid,
|
|
119411
|
+
uptime: w3.uptime,
|
|
119412
|
+
metrics: {
|
|
119413
|
+
cpu: (w3.loadAvg[0] || 0) * 100,
|
|
119414
|
+
cores: 0,
|
|
119415
|
+
ram: {
|
|
119416
|
+
rss: parseInt(w3.memory.rss || "0", 10),
|
|
119417
|
+
heapUsed: parseInt(w3.memory.heapUsed || "0", 10),
|
|
119418
|
+
total: 0
|
|
119419
|
+
}
|
|
119420
|
+
},
|
|
119421
|
+
queues: w3.queues.map((q3) => ({
|
|
119422
|
+
name: q3,
|
|
119423
|
+
size: { waiting: 0, active: 0, failed: 0, delayed: 0 }
|
|
119424
|
+
})),
|
|
119425
|
+
meta: {}
|
|
119426
|
+
}));
|
|
119427
|
+
return c3.json({ workers: [...pulseWorkers, ...formattedLegacy] });
|
|
119036
119428
|
} catch (_err) {
|
|
119429
|
+
console.error(_err);
|
|
119037
119430
|
return c3.json({ error: "Failed to fetch workers" }, 500);
|
|
119038
119431
|
}
|
|
119039
119432
|
});
|