biz-a-cli 2.3.79-15211 → 2.3.79-15212

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.
@@ -0,0 +1,62 @@
1
+ import { io } from "socket.io-client";
2
+ import { workerEvents, workerStats } from "../worker/cliWorkerPool.js";
3
+
4
+ export class CLI_Agent {
5
+ constructor(dispatcherUrl, services = "ALL") {
6
+ const url = dispatcherUrl.startsWith("http")
7
+ ? dispatcherUrl
8
+ : `http://${dispatcherUrl}`;
9
+
10
+ this.services = services.split(",").map((s) => s.trim().toUpperCase());
11
+
12
+ console.log(`[CLI Agent] Connecting to Message Broker at ${url}...`);
13
+
14
+ this.socketBus = io(`${url}/message-broker`, {
15
+ reconnectionDelay: 5000,
16
+ reconnectionDelayMax: 10000,
17
+ });
18
+
19
+ this.socketBus.on("connect", () => {
20
+ console.log(
21
+ `[CLI Agent] Successfully connected. Listening for triggers...`,
22
+ );
23
+
24
+ // 1. Register Capabilities
25
+ this.socketBus.emit("ESB_AGENT_REGISTER", {
26
+ services: this.services,
27
+ });
28
+
29
+ // 2. The Workload Heartbeat
30
+ if (this.statsInterval) clearInterval(this.statsInterval);
31
+ this.statsInterval = setInterval(() => {
32
+ const stats = workerStats();
33
+ const active = stats.cliScript
34
+ ? stats.cliScript.activeTasks
35
+ : 0;
36
+ const pending = stats.cliScript
37
+ ? stats.cliScript.pendingTasks
38
+ : 0;
39
+ this.socketBus.emit("ESB_AGENT_STATS", {
40
+ activeTasks: active + pending,
41
+ });
42
+ }, 2000);
43
+ });
44
+
45
+ this.socketBus.on("disconnect", () => {
46
+ if (this.statsInterval) clearInterval(this.statsInterval);
47
+ });
48
+
49
+ // 3. Strict Upstream Routing
50
+ workerEvents.on("IPC_RELAY", (topic, payload) => {
51
+ this.socketBus.emit("ESB_UPSTREAM_RELAY", { topic, payload });
52
+ });
53
+ }
54
+
55
+ on(eventName, callback) {
56
+ this.socketBus.on(eventName, callback);
57
+ }
58
+
59
+ publish(topic, payload = null, ackCallback = null) {
60
+ this.socketBus.emit(topic, payload, ackCallback);
61
+ }
62
+ }
@@ -0,0 +1,137 @@
1
+ import { EventEmitter } from "node:events";
2
+ import { workerEvents } from "../worker/cliWorkerPool.js";
3
+
4
+ export class CLI_Dispatcher {
5
+ constructor(mode, ioServerInstance = null) {
6
+ this.mode = mode || "monolithic";
7
+ this.agentRegistry = new Map(); // The Scoreboard
8
+
9
+ if (this.mode === "monolithic") {
10
+ this.localBus = new EventEmitter();
11
+ }
12
+
13
+ console.log(`[Message Broker] Initialized in '${this.mode}' mode.`);
14
+
15
+ if (this.mode === "dispatcher" && ioServerInstance) {
16
+ this.agentNamespace = ioServerInstance.of("/message-broker");
17
+
18
+ this.agentNamespace.on("connection", (socket) => {
19
+ console.log(
20
+ `[Message Broker] Remote Agent connected: ${socket.id}`,
21
+ );
22
+
23
+ this.agentRegistry.set(socket.id, {
24
+ activeTasks: 0,
25
+ services: [],
26
+ });
27
+
28
+ socket.on("ESB_AGENT_REGISTER", (data) => {
29
+ if (this.agentRegistry.has(socket.id)) {
30
+ this.agentRegistry.get(socket.id).services =
31
+ data.services || [];
32
+ }
33
+ });
34
+
35
+ socket.on("ESB_AGENT_STATS", (data) => {
36
+ if (this.agentRegistry.has(socket.id)) {
37
+ this.agentRegistry.get(socket.id).activeTasks =
38
+ data.activeTasks || 0;
39
+ }
40
+ });
41
+
42
+ socket.on("ESB_UPSTREAM_RELAY", ({ topic, payload }) => {
43
+ this.balanceAndDispatchEvent(topic, payload);
44
+ });
45
+
46
+ socket.on("disconnect", () => {
47
+ console.log(
48
+ `[Message Broker] Remote Agent disconnected: ${socket.id}`,
49
+ );
50
+ this.agentRegistry.delete(socket.id);
51
+ });
52
+ });
53
+ }
54
+
55
+ workerEvents.on("IPC_RELAY", (topic, payload) => {
56
+ this.balanceAndDispatchEvent(topic, payload);
57
+ });
58
+ }
59
+
60
+ balanceAndDispatchEvent(topic, payload) {
61
+ // --- EMIT TO SPECIFIC BIZ-A CLIENT ---
62
+ // ex: this.lib.emitClient(scriptData.clientSockId, scriptData.eventUUIDName, { status: "Done!" });
63
+ if (topic === "emitClient") {
64
+ console.log(
65
+ `\n[Future Dev] Target: Biz-A Client Socket ID [${payload?.clientSockId}]`,
66
+ );
67
+ console.log(`[Future Dev] Event: ${payload?.eventUUIDName}`);
68
+ console.log(`[Future Dev] Payload:`, payload?.payload, `\n`);
69
+ // TODO: this.agentNamespace.to(payload.clientSockId).emit(payload.eventUUIDName, payload.payload);
70
+ return;
71
+ }
72
+
73
+ // --- EMIT TO ALL BIZ-A CLIENT ---
74
+ // ex: this.lib.broadcastClient("ui:alert", { message: "System maintenance in 5 mins" });
75
+ if (topic === "broadcastClient") {
76
+ console.log(`\n[Future Dev] Broadcast: ALL Clients in CLIENT_ROOM`);
77
+ console.log(`[Future Dev] Event: ${payload?.topic}`);
78
+ console.log(`[Future Dev] Payload:`, payload?.payload, `\n`);
79
+ // TODO: this.agentNamespace.to("clientRoom").emit(payload.topic, payload.payload);
80
+ return;
81
+ }
82
+
83
+ // --- INTERNAL SYSTEM ROUTING ---
84
+ // ex : this.lib.emitCLI("email:send", data);
85
+ if (this.mode === "monolithic" && this.localBus) {
86
+ this.localBus.emit(topic, payload);
87
+ return;
88
+ }
89
+
90
+ // --- ROUTING TO BEST AGENT (based on workload at each agent) ---
91
+ if (this.mode === "dispatcher" && this.agentNamespace) {
92
+ const requiredService = topic.split(":")[0].toUpperCase();
93
+ let bestAgentId = null;
94
+ let minTasks = Infinity;
95
+
96
+ for (const [socketId, stats] of this.agentRegistry.entries()) {
97
+ const canHandle =
98
+ stats.services.includes("ALL") ||
99
+ stats.services.includes(requiredService);
100
+ if (canHandle && stats.activeTasks < minTasks) {
101
+ minTasks = stats.activeTasks;
102
+ bestAgentId = socketId;
103
+ }
104
+ }
105
+
106
+ if (bestAgentId) {
107
+ console.log(
108
+ `[Load Balancer] Routing '${topic}' to Agent ${bestAgentId} (Active Tasks: ${minTasks})`,
109
+ );
110
+ this.agentNamespace.to(bestAgentId).emit(topic, payload);
111
+ } else {
112
+ console.error(
113
+ `[Load Balancer] WARNING: No connected Agent supports '${requiredService}'`,
114
+ );
115
+ }
116
+ }
117
+ }
118
+
119
+ start(intervalMs = 5000) {
120
+ setInterval(() => {
121
+ this.publish("sys:tick");
122
+ }, intervalMs);
123
+ this.publish("sys:tick");
124
+ }
125
+
126
+ on(eventName, callback) {
127
+ if (this.localBus) this.localBus.on(eventName, callback);
128
+ }
129
+
130
+ publish(topic, payload = null, ackCallback = null) {
131
+ if (this.mode === "monolithic" && this.localBus) {
132
+ this.localBus.emit(topic, payload, ackCallback);
133
+ } else if (this.mode === "dispatcher" && this.agentNamespace) {
134
+ this.agentNamespace.emit(topic, payload, ackCallback);
135
+ }
136
+ }
137
+ }
@@ -0,0 +1,23 @@
1
+ import { CLI_Dispatcher } from "./dispatcher.js";
2
+ import { CLI_Agent } from "./agent.js";
3
+ import { initBpmAgent } from "../engine/bpm/bpm-agent.js";
4
+
5
+ export function bootMicroservices(argv, ioServerInstance = null) {
6
+ const services = argv.services || "ALL";
7
+
8
+ if (argv.mode === "monolithic") {
9
+ const broker = new CLI_Dispatcher("monolithic");
10
+ initBpmAgent(broker, "ALL");
11
+ broker.start(5000);
12
+ return broker;
13
+ } else if (argv.mode === "dispatcher") {
14
+ const broker = new CLI_Dispatcher("dispatcher", ioServerInstance);
15
+ initBpmAgent(broker, services);
16
+ broker.start(5000);
17
+ return broker;
18
+ } else if (argv.mode === "agent") {
19
+ const genericAgent = new CLI_Agent(argv.server, services);
20
+ initBpmAgent(genericAgent, services);
21
+ return genericAgent;
22
+ }
23
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "biz-a-cli",
3
- "version": "2.3.79-15211",
3
+ "version": "2.3.79-15212",
4
4
  "description": "",
5
5
  "main": "bin/index.js",
6
6
  "type": "module",
@@ -14,6 +14,7 @@
14
14
  "engine/**/*",
15
15
  "envs/**/*",
16
16
  "key/**/*",
17
+ "message-broker/**/*",
17
18
  "migrations/**/*",
18
19
  "scheduler/**/*",
19
20
  "worker/**/*",