@agentunion/kite 1.0.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/__init__.py +1 -0
- package/__main__.py +15 -0
- package/cli.js +70 -0
- package/core/__init__.py +0 -0
- package/core/__pycache__/__init__.cpython-313.pyc +0 -0
- package/core/event_hub/BENCHMARK.md +94 -0
- package/core/event_hub/__init__.py +0 -0
- package/core/event_hub/__pycache__/__init__.cpython-313.pyc +0 -0
- package/core/event_hub/__pycache__/bench.cpython-313.pyc +0 -0
- package/core/event_hub/__pycache__/bench_perf.cpython-313.pyc +0 -0
- package/core/event_hub/__pycache__/dedup.cpython-313.pyc +0 -0
- package/core/event_hub/__pycache__/entry.cpython-313.pyc +0 -0
- package/core/event_hub/__pycache__/hub.cpython-313.pyc +0 -0
- package/core/event_hub/__pycache__/router.cpython-313.pyc +0 -0
- package/core/event_hub/__pycache__/server.cpython-313.pyc +0 -0
- package/core/event_hub/bench.py +459 -0
- package/core/event_hub/bench_extreme.py +308 -0
- package/core/event_hub/bench_perf.py +350 -0
- package/core/event_hub/bench_results/.gitkeep +0 -0
- package/core/event_hub/bench_results/2026-02-28_13-26-48.json +51 -0
- package/core/event_hub/bench_results/2026-02-28_13-44-45.json +51 -0
- package/core/event_hub/bench_results/2026-02-28_13-45-39.json +51 -0
- package/core/event_hub/dedup.py +31 -0
- package/core/event_hub/entry.py +113 -0
- package/core/event_hub/hub.py +263 -0
- package/core/event_hub/module.md +21 -0
- package/core/event_hub/router.py +21 -0
- package/core/event_hub/server.py +138 -0
- package/core/event_hub_bench/entry.py +371 -0
- package/core/event_hub_bench/module.md +25 -0
- package/core/launcher/__init__.py +0 -0
- package/core/launcher/__pycache__/__init__.cpython-313.pyc +0 -0
- package/core/launcher/__pycache__/entry.cpython-313.pyc +0 -0
- package/core/launcher/__pycache__/module_scanner.cpython-313.pyc +0 -0
- package/core/launcher/__pycache__/process_manager.cpython-313.pyc +0 -0
- package/core/launcher/data/log/lifecycle.jsonl +1045 -0
- package/core/launcher/data/processes_14752.json +32 -0
- package/core/launcher/data/token.txt +1 -0
- package/core/launcher/entry.py +965 -0
- package/core/launcher/module.md +37 -0
- package/core/launcher/module_scanner.py +253 -0
- package/core/launcher/process_manager.py +435 -0
- package/core/registry/__init__.py +0 -0
- package/core/registry/__pycache__/__init__.cpython-313.pyc +0 -0
- package/core/registry/__pycache__/entry.cpython-313.pyc +0 -0
- package/core/registry/__pycache__/server.cpython-313.pyc +0 -0
- package/core/registry/__pycache__/store.cpython-313.pyc +0 -0
- package/core/registry/data/port.txt +1 -0
- package/core/registry/data/port_14752.txt +1 -0
- package/core/registry/data/port_484.txt +1 -0
- package/core/registry/entry.py +73 -0
- package/core/registry/module.md +30 -0
- package/core/registry/server.py +256 -0
- package/core/registry/store.py +232 -0
- package/extensions/__init__.py +0 -0
- package/extensions/__pycache__/__init__.cpython-313.pyc +0 -0
- package/extensions/services/__init__.py +0 -0
- package/extensions/services/__pycache__/__init__.cpython-313.pyc +0 -0
- package/extensions/services/watchdog/__init__.py +0 -0
- package/extensions/services/watchdog/__pycache__/__init__.cpython-313.pyc +0 -0
- package/extensions/services/watchdog/__pycache__/entry.cpython-313.pyc +0 -0
- package/extensions/services/watchdog/__pycache__/monitor.cpython-313.pyc +0 -0
- package/extensions/services/watchdog/__pycache__/server.cpython-313.pyc +0 -0
- package/extensions/services/watchdog/entry.py +143 -0
- package/extensions/services/watchdog/module.md +25 -0
- package/extensions/services/watchdog/monitor.py +420 -0
- package/extensions/services/watchdog/server.py +167 -0
- package/main.py +17 -0
- package/package.json +27 -0
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Event Hub Benchmark module entry point.
|
|
3
|
+
Discovers hub via Registry, runs benchmarks, saves results, exits.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import asyncio
|
|
7
|
+
import json
|
|
8
|
+
import os
|
|
9
|
+
import platform
|
|
10
|
+
import sys
|
|
11
|
+
import threading
|
|
12
|
+
import time
|
|
13
|
+
from datetime import datetime, timezone
|
|
14
|
+
|
|
15
|
+
import statistics
|
|
16
|
+
import uuid
|
|
17
|
+
|
|
18
|
+
import httpx
|
|
19
|
+
import websockets
|
|
20
|
+
|
|
21
|
+
_this_dir = os.path.dirname(os.path.abspath(__file__))
|
|
22
|
+
_project_root = os.path.dirname(os.path.dirname(_this_dir))
|
|
23
|
+
if _project_root not in sys.path:
|
|
24
|
+
sys.path.insert(0, _project_root)
|
|
25
|
+
|
|
26
|
+
RESULTS_DIR = os.path.join(_project_root, "core", "event_hub", "bench_results")
|
|
27
|
+
TAG = "[event_hub_bench]"
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _discover_hub(registry_url: str, token: str, timeout: float = 30) -> str | None:
|
|
31
|
+
"""Poll registry until event_hub is found. Returns ws:// URL or None."""
|
|
32
|
+
headers = {"Authorization": f"Bearer {token}"}
|
|
33
|
+
deadline = time.time() + timeout
|
|
34
|
+
while time.time() < deadline:
|
|
35
|
+
try:
|
|
36
|
+
resp = httpx.get(
|
|
37
|
+
f"{registry_url}/lookup/event_hub",
|
|
38
|
+
headers=headers, timeout=5,
|
|
39
|
+
)
|
|
40
|
+
if resp.status_code == 200:
|
|
41
|
+
info = resp.json()
|
|
42
|
+
ws_url = (info.get("metadata") or {}).get("ws_endpoint")
|
|
43
|
+
if ws_url:
|
|
44
|
+
return ws_url
|
|
45
|
+
except Exception:
|
|
46
|
+
pass
|
|
47
|
+
time.sleep(1)
|
|
48
|
+
return None
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def _get_hub_stats(ws_url: str) -> dict:
|
|
52
|
+
"""Fetch hub /stats via HTTP (derive from ws:// URL)."""
|
|
53
|
+
http_url = ws_url.replace("ws://", "http://").rsplit("/ws", 1)[0]
|
|
54
|
+
try:
|
|
55
|
+
resp = httpx.get(f"{http_url}/stats", timeout=5)
|
|
56
|
+
if resp.status_code == 200:
|
|
57
|
+
return resp.json()
|
|
58
|
+
except Exception:
|
|
59
|
+
pass
|
|
60
|
+
return {}
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _sample_hub_resources(ws_url: str) -> dict:
|
|
64
|
+
"""Sample hub process CPU/memory via psutil. Returns {} if unavailable."""
|
|
65
|
+
try:
|
|
66
|
+
import psutil
|
|
67
|
+
except ImportError:
|
|
68
|
+
return {"error": "psutil not installed"}
|
|
69
|
+
http_url = ws_url.replace("ws://", "http://").rsplit("/ws", 1)[0]
|
|
70
|
+
port = int(http_url.rsplit(":", 1)[1].split("/")[0])
|
|
71
|
+
for conn in psutil.net_connections(kind="tcp"):
|
|
72
|
+
if conn.laddr.port == port and conn.status == "LISTEN":
|
|
73
|
+
try:
|
|
74
|
+
p = psutil.Process(conn.pid)
|
|
75
|
+
mem = p.memory_info()
|
|
76
|
+
return {
|
|
77
|
+
"pid": conn.pid,
|
|
78
|
+
"cpu_percent": p.cpu_percent(interval=1),
|
|
79
|
+
"rss_mb": round(mem.rss / 1048576, 1),
|
|
80
|
+
"vms_mb": round(mem.vms / 1048576, 1),
|
|
81
|
+
"threads": p.num_threads(),
|
|
82
|
+
}
|
|
83
|
+
except Exception:
|
|
84
|
+
pass
|
|
85
|
+
return {"error": "hub process not found"}
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
# ── WebSocket client ──
|
|
89
|
+
|
|
90
|
+
class WsClient:
|
|
91
|
+
"""Lightweight async WebSocket client for hub benchmarks."""
|
|
92
|
+
|
|
93
|
+
def __init__(self, ws_url: str, token: str, client_id: str):
|
|
94
|
+
self.url = f"{ws_url}?token={token}&id={client_id}"
|
|
95
|
+
self.id = client_id
|
|
96
|
+
self.ws = None
|
|
97
|
+
|
|
98
|
+
async def connect(self):
|
|
99
|
+
self.ws = await websockets.connect(self.url, max_size=None)
|
|
100
|
+
|
|
101
|
+
async def subscribe(self, patterns: list[str]):
|
|
102
|
+
await self.ws.send(json.dumps({"type": "subscribe", "events": patterns}))
|
|
103
|
+
|
|
104
|
+
async def publish(self, event_type: str, data: dict) -> str:
|
|
105
|
+
eid = str(uuid.uuid4())
|
|
106
|
+
await self.ws.send(json.dumps({
|
|
107
|
+
"type": "event", "event_id": eid, "event": event_type,
|
|
108
|
+
"source": self.id,
|
|
109
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
110
|
+
"data": data,
|
|
111
|
+
}))
|
|
112
|
+
return eid
|
|
113
|
+
|
|
114
|
+
async def recv(self, timeout=5.0):
|
|
115
|
+
try:
|
|
116
|
+
return json.loads(await asyncio.wait_for(self.ws.recv(), timeout=timeout))
|
|
117
|
+
except Exception:
|
|
118
|
+
return None
|
|
119
|
+
|
|
120
|
+
async def close(self):
|
|
121
|
+
if self.ws:
|
|
122
|
+
await self.ws.close()
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
# ── Benchmark runner ──
|
|
126
|
+
|
|
127
|
+
class BenchRunner:
|
|
128
|
+
def __init__(self, ws_url: str, token: str):
|
|
129
|
+
self.ws_url = ws_url
|
|
130
|
+
self.token = token
|
|
131
|
+
self.results = {}
|
|
132
|
+
|
|
133
|
+
async def _make_client(self, name: str) -> WsClient:
|
|
134
|
+
c = WsClient(self.ws_url, self.token, name)
|
|
135
|
+
await c.connect()
|
|
136
|
+
return c
|
|
137
|
+
|
|
138
|
+
# ── Throughput: burst N events, measure hub processing rate ──
|
|
139
|
+
|
|
140
|
+
async def bench_throughput(self, n: int = 10000):
|
|
141
|
+
print(f"{TAG} Throughput test: {n} events...")
|
|
142
|
+
pub = await self._make_client("bench_tp_pub")
|
|
143
|
+
sub = await self._make_client("bench_tp_sub")
|
|
144
|
+
await sub.subscribe(["bench.tp.*"])
|
|
145
|
+
await asyncio.sleep(0.2)
|
|
146
|
+
|
|
147
|
+
recvd = 0
|
|
148
|
+
stop = asyncio.Event()
|
|
149
|
+
|
|
150
|
+
async def _recv():
|
|
151
|
+
nonlocal recvd
|
|
152
|
+
while not stop.is_set():
|
|
153
|
+
try:
|
|
154
|
+
raw = await asyncio.wait_for(sub.ws.recv(), timeout=0.5)
|
|
155
|
+
if '"event"' in raw and '"ack"' not in raw:
|
|
156
|
+
recvd += 1
|
|
157
|
+
except Exception:
|
|
158
|
+
pass
|
|
159
|
+
|
|
160
|
+
async def _drain_acks():
|
|
161
|
+
while not stop.is_set():
|
|
162
|
+
try:
|
|
163
|
+
await asyncio.wait_for(pub.ws.recv(), timeout=0.5)
|
|
164
|
+
except Exception:
|
|
165
|
+
pass
|
|
166
|
+
|
|
167
|
+
recv_task = asyncio.create_task(_recv())
|
|
168
|
+
ack_task = asyncio.create_task(_drain_acks())
|
|
169
|
+
|
|
170
|
+
hub_before = (_get_hub_stats(self.ws_url).get("counters") or {})
|
|
171
|
+
|
|
172
|
+
t0 = time.time()
|
|
173
|
+
for i in range(n):
|
|
174
|
+
await pub.publish("bench.tp.test", {"i": i})
|
|
175
|
+
send_time = time.time() - t0
|
|
176
|
+
|
|
177
|
+
deadline = time.time() + max(15, n / 300)
|
|
178
|
+
while recvd < n and time.time() < deadline:
|
|
179
|
+
await asyncio.sleep(0.1)
|
|
180
|
+
total_time = time.time() - t0
|
|
181
|
+
|
|
182
|
+
stop.set()
|
|
183
|
+
await recv_task
|
|
184
|
+
ack_task.cancel()
|
|
185
|
+
|
|
186
|
+
hub_after = (_get_hub_stats(self.ws_url).get("counters") or {})
|
|
187
|
+
|
|
188
|
+
await pub.close()
|
|
189
|
+
await sub.close()
|
|
190
|
+
|
|
191
|
+
self.results["throughput"] = {
|
|
192
|
+
"events": n,
|
|
193
|
+
"send_rate": round(n / send_time),
|
|
194
|
+
"recv_rate": round(recvd / total_time) if total_time > 0 else 0,
|
|
195
|
+
"client_recv": recvd,
|
|
196
|
+
"hub_queued": hub_after.get("events_queued", 0) - hub_before.get("events_queued", 0),
|
|
197
|
+
"hub_routed": hub_after.get("events_routed", 0) - hub_before.get("events_routed", 0),
|
|
198
|
+
"send_time_s": round(send_time, 2),
|
|
199
|
+
"total_time_s": round(total_time, 2),
|
|
200
|
+
}
|
|
201
|
+
print(f"{TAG} send_rate={self.results['throughput']['send_rate']} evt/s, "
|
|
202
|
+
f"recv={recvd}/{n}, time={round(total_time, 1)}s")
|
|
203
|
+
|
|
204
|
+
# ── Latency: sequential pub→recv round-trip ──
|
|
205
|
+
|
|
206
|
+
async def bench_latency(self, n: int = 200):
|
|
207
|
+
print(f"{TAG} Latency test: {n} samples...")
|
|
208
|
+
pub = await self._make_client("bench_lat_pub")
|
|
209
|
+
sub = await self._make_client("bench_lat_sub")
|
|
210
|
+
await sub.subscribe(["bench.lat.*"])
|
|
211
|
+
await asyncio.sleep(0.2)
|
|
212
|
+
|
|
213
|
+
latencies = []
|
|
214
|
+
for i in range(n):
|
|
215
|
+
t0 = time.time()
|
|
216
|
+
await pub.publish("bench.lat.test", {"i": i})
|
|
217
|
+
await pub.recv(timeout=2) # ack
|
|
218
|
+
msg = await sub.recv(timeout=2)
|
|
219
|
+
if msg and msg.get("type") == "event":
|
|
220
|
+
latencies.append((time.time() - t0) * 1000)
|
|
221
|
+
|
|
222
|
+
await pub.close()
|
|
223
|
+
await sub.close()
|
|
224
|
+
|
|
225
|
+
if latencies:
|
|
226
|
+
latencies.sort()
|
|
227
|
+
self.results["latency"] = {
|
|
228
|
+
"samples": len(latencies),
|
|
229
|
+
"avg_ms": round(statistics.mean(latencies), 2),
|
|
230
|
+
"p50_ms": round(latencies[len(latencies) // 2], 2),
|
|
231
|
+
"p95_ms": round(latencies[int(len(latencies) * 0.95)], 2),
|
|
232
|
+
"p99_ms": round(latencies[int(len(latencies) * 0.99)], 2),
|
|
233
|
+
}
|
|
234
|
+
print(f"{TAG} avg={self.results['latency']['avg_ms']}ms, "
|
|
235
|
+
f"p50={self.results['latency']['p50_ms']}ms, "
|
|
236
|
+
f"p99={self.results['latency']['p99_ms']}ms")
|
|
237
|
+
|
|
238
|
+
# ── Fan-out: 1 pub, N subs ──
|
|
239
|
+
|
|
240
|
+
async def bench_fanout(self, n_events: int = 2000):
|
|
241
|
+
for n_subs in [1, 5, 10, 50]:
|
|
242
|
+
print(f"{TAG} Fan-out x{n_subs}: {n_events} events...")
|
|
243
|
+
pub = await self._make_client("bench_fo_pub")
|
|
244
|
+
subs = []
|
|
245
|
+
for i in range(n_subs):
|
|
246
|
+
s = await self._make_client(f"bench_fo_sub_{i}")
|
|
247
|
+
await s.subscribe(["bench.fo.*"])
|
|
248
|
+
subs.append(s)
|
|
249
|
+
await asyncio.sleep(0.3)
|
|
250
|
+
|
|
251
|
+
counts = [0] * n_subs
|
|
252
|
+
stop = asyncio.Event()
|
|
253
|
+
|
|
254
|
+
async def _recv(idx, client):
|
|
255
|
+
while not stop.is_set():
|
|
256
|
+
try:
|
|
257
|
+
raw = await asyncio.wait_for(client.ws.recv(), timeout=0.5)
|
|
258
|
+
if '"event"' in raw and '"ack"' not in raw:
|
|
259
|
+
counts[idx] += 1
|
|
260
|
+
except Exception:
|
|
261
|
+
pass
|
|
262
|
+
|
|
263
|
+
tasks = [asyncio.create_task(_recv(i, s)) for i, s in enumerate(subs)]
|
|
264
|
+
ack_stop = asyncio.Event()
|
|
265
|
+
|
|
266
|
+
async def _drain():
|
|
267
|
+
while not ack_stop.is_set():
|
|
268
|
+
try:
|
|
269
|
+
await asyncio.wait_for(pub.ws.recv(), timeout=0.5)
|
|
270
|
+
except Exception:
|
|
271
|
+
pass
|
|
272
|
+
|
|
273
|
+
ack_task = asyncio.create_task(_drain())
|
|
274
|
+
|
|
275
|
+
t0 = time.time()
|
|
276
|
+
for i in range(n_events):
|
|
277
|
+
await pub.publish("bench.fo.test", {"i": i})
|
|
278
|
+
send_time = time.time() - t0
|
|
279
|
+
|
|
280
|
+
await asyncio.sleep(max(3, n_events * n_subs / 3000))
|
|
281
|
+
stop.set()
|
|
282
|
+
ack_stop.set()
|
|
283
|
+
for t in tasks:
|
|
284
|
+
await t
|
|
285
|
+
ack_task.cancel()
|
|
286
|
+
|
|
287
|
+
await pub.close()
|
|
288
|
+
for s in subs:
|
|
289
|
+
await s.close()
|
|
290
|
+
|
|
291
|
+
avg_recv = sum(counts) / n_subs if n_subs else 0
|
|
292
|
+
self.results[f"fanout_{n_subs}"] = {
|
|
293
|
+
"subs": n_subs,
|
|
294
|
+
"events": n_events,
|
|
295
|
+
"send_rate": round(n_events / send_time) if send_time > 0 else 0,
|
|
296
|
+
"avg_recv": round(avg_recv),
|
|
297
|
+
"min_recv": min(counts),
|
|
298
|
+
}
|
|
299
|
+
print(f"{TAG} subs={n_subs}, avg_recv={round(avg_recv)}/{n_events}, "
|
|
300
|
+
f"min={min(counts)}")
|
|
301
|
+
|
|
302
|
+
# ── Save results ──
|
|
303
|
+
|
|
304
|
+
def save(self, ws_url: str):
|
|
305
|
+
os.makedirs(RESULTS_DIR, exist_ok=True)
|
|
306
|
+
now = datetime.now()
|
|
307
|
+
filepath = os.path.join(RESULTS_DIR, now.strftime("%Y-%m-%d_%H-%M-%S") + ".json")
|
|
308
|
+
|
|
309
|
+
hub_stats = _get_hub_stats(ws_url)
|
|
310
|
+
resources = _sample_hub_resources(ws_url)
|
|
311
|
+
|
|
312
|
+
data = {
|
|
313
|
+
"timestamp": now.isoformat(),
|
|
314
|
+
"env": {
|
|
315
|
+
"platform": sys.platform,
|
|
316
|
+
"python": platform.python_version(),
|
|
317
|
+
},
|
|
318
|
+
"hub_resources": resources,
|
|
319
|
+
"hub_counters": hub_stats.get("counters", {}),
|
|
320
|
+
**self.results,
|
|
321
|
+
}
|
|
322
|
+
with open(filepath, "w", encoding="utf-8") as f:
|
|
323
|
+
json.dump(data, f, indent=2, ensure_ascii=False)
|
|
324
|
+
print(f"{TAG} Results saved: {filepath}")
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
# ── Entry point ──
|
|
328
|
+
|
|
329
|
+
async def _run(ws_url: str, token: str):
|
|
330
|
+
bench = BenchRunner(ws_url, token)
|
|
331
|
+
await bench.bench_throughput()
|
|
332
|
+
await bench.bench_latency()
|
|
333
|
+
await bench.bench_fanout()
|
|
334
|
+
bench.save(ws_url)
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
def main():
|
|
338
|
+
# Read boot_info from stdin
|
|
339
|
+
token = ""
|
|
340
|
+
registry_port = 0
|
|
341
|
+
try:
|
|
342
|
+
line = sys.stdin.readline().strip()
|
|
343
|
+
if line:
|
|
344
|
+
boot = json.loads(line)
|
|
345
|
+
token = boot.get("token", "")
|
|
346
|
+
registry_port = boot.get("registry_port", 0)
|
|
347
|
+
except Exception:
|
|
348
|
+
pass
|
|
349
|
+
|
|
350
|
+
if not token or not registry_port:
|
|
351
|
+
print(f"{TAG} ERROR: Missing token or registry_port")
|
|
352
|
+
sys.exit(1)
|
|
353
|
+
|
|
354
|
+
registry_url = f"http://127.0.0.1:{registry_port}"
|
|
355
|
+
print(f"{TAG} Discovering event_hub via registry...")
|
|
356
|
+
|
|
357
|
+
ws_url = _discover_hub(registry_url, token)
|
|
358
|
+
if not ws_url:
|
|
359
|
+
print(f"{TAG} ERROR: event_hub not found")
|
|
360
|
+
sys.exit(1)
|
|
361
|
+
|
|
362
|
+
print(f"{TAG} Hub found: {ws_url}")
|
|
363
|
+
print(f"{TAG} Starting benchmarks...")
|
|
364
|
+
|
|
365
|
+
asyncio.run(_run(ws_url, token))
|
|
366
|
+
|
|
367
|
+
print(f"{TAG} Benchmarks complete, exiting.")
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
if __name__ == "__main__":
|
|
371
|
+
main()
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: event_hub_bench
|
|
3
|
+
display_name: Event Hub Benchmark
|
|
4
|
+
version: "1.0"
|
|
5
|
+
type: tool
|
|
6
|
+
state: enabled
|
|
7
|
+
runtime: python
|
|
8
|
+
entry: entry.py
|
|
9
|
+
events: []
|
|
10
|
+
subscriptions: []
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# Event Hub Benchmark
|
|
14
|
+
|
|
15
|
+
事件中心性能基准测试模块。
|
|
16
|
+
|
|
17
|
+
- 启用后随 Kite 启动自动运行基准测试
|
|
18
|
+
- 通过 Registry 发现 Event Hub,以真实模块身份连接
|
|
19
|
+
- 多线程模拟多个 publisher/subscriber 压测 hub
|
|
20
|
+
- 监控 hub 进程 CPU/内存占用
|
|
21
|
+
- 结果保存到 `core/event_hub/bench_results/`
|
|
22
|
+
- 测试完成后自动退出
|
|
23
|
+
|
|
24
|
+
启用:将 `state` 改为 `enabled`
|
|
25
|
+
停用:将 `state` 改为 `disabled`
|
|
File without changes
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|