Grade muse-glimmer-28b full 7-prompt battery — new benchmark leader

7 entries (30→37 total). Muse Glimmer 28B (GGUF) avg 80.7 — the strongest
model in the benchmark, 6/7 prompts Minor Logic Flaws:
  lfu 76 | webhook 81 | automation 89 | rust 85 | data 88 | tts 58 | mcp 88

Standout results:
- rust 85 (KAT 36, Qwen3-Coder 54) — real tokio channels (mpsc::channel, not
  hallucinated mpsc::bounded), two-tier CancellationToken, zero clippy lints;
  one-line E0507 compile fix.
- automation 89 — first model to print a correct summary (98/2/0/100);
  atomic temp+fsync+rename checkpointing.
- data 88 edges out Gemma-26B's 86; mcp 88 sets the bar on a new prompt.
Only weak spot: tts 58 (backpressure raises instead of awaits, like Qwen3-Coder).

Captured via the native /api/v1/chat fix (real tok/sec + TTFT). Slow
deep-thinker: ~17-19 t/s, 5-9 min/prompt, ~5-9k tokens incl. reasoning.

Also gitignore checkpoint.json (automation test runtime artifact).

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Aygea
2026-08-10 13:13:54 -07:00
co-authored by Claude
parent 3507d33006
commit 2f99dd1e35
10 changed files with 1769 additions and 7 deletions
+2
View File
@@ -21,3 +21,5 @@ __pycache__/
# --- Webhook secret (NEVER commit) ---
.webhook.secret
# automation prompt test artifact (runtime-generated)
checkpoint.json
+234
View File
@@ -1041,6 +1041,240 @@
"patch_code": "# 1. Add a real acquire-timeout / pool-exhaustion test:\nasync def test_pool_exhaustion():\n state = MockDatabaseState()\n pool = MockPool(max_size=5, state=state)\n held = [await pool.acquire() for _ in range(5)]\n try:\n with pytest.raises(PoolExhaustedError):\n await asyncio.wait_for(pool.acquire(), timeout=3.0)\n finally:\n for c in held: await c.release()\n assert pool.in_use == 0\n\n# 2. Derive in_use from the semaphore so the counter cannot drift:\n@property\ndef in_use(self) -> int:\n return self.max_size - self._semaphore._value",
"timestamp": "2026-07-29T04:30:00Z",
"ttft_note": null
},
{
"id": "muse-glimmer-28b-gguf-lfu",
"prompt_id": "lfu",
"model_name": "Muse Glimmer 28B",
"quant": "GGUF",
"param_size": "28B",
"format": "gguf",
"lang": "python",
"filename": "outputs/muse-glimmer-28b-gguf-lfu.py",
"tok_sec": 19.38,
"ttft_sec": 3.55,
"total_tokens": 9095,
"speed_caveat": "Slow deep-thinker: ~17-19 t/s, 5-9 min/prompt, ~5-9k tokens incl. reasoning. Fast for quality, not throughput.",
"tests_pass": false,
"total_score": 76,
"breakdown": {
"complexity": 18,
"concurrency": 15,
"isolation": 12,
"memory_edge_cases": 16,
"test_integrity": 15
},
"verdict": "Minor Logic Flaws",
"best_for": "The strongest LFU result from a non-coder model in this benchmark — nails true O(1) freq-bucket eviction with correct min_freq tracking and __slots__ where both specialist coder models (KAT, Qwen3-Coder) failed catastrophically. Let down by one signature bug: rollback() is sync but awaited.",
"critical_bugs": [
"rollback() is a sync method (line 213, 'def rollback') returning None, but the test awaits it (line 252, 'await tx2.rollback()') -> TypeError: object NoneType can't be used in 'await' expression. The whole test suite crashes at the rollback assertion. Fix: make it 'async def rollback()'.",
"_update_min_freq walks min_freq upward indefinitely with no upper bound; harmless while the cache is non-empty but an unbounded loop on a fully-drained cache.",
"No transaction lifecycle guard: after commit() or rollback(), a stale Transaction handle can still call put/get/delete/commit again (double-commit) with no error.",
"Transaction.get/commit acquire self.cache.lock directly — transactions share the cache's single lock rather than an isolation lock; correct for the buffer model but couples tx lifetime to cache lock contention."
],
"patch_code": "# Fix 1 (fatal): rollback must be async to match 'await tx2.rollback()'\nasync def rollback(self):\n self.pending_puts.clear()\n self.pending_deletes.clear()\n\n# Fix 2: bound _update_min_freq against a drained cache\ndef _update_min_freq(self):\n if not self.freq_map:\n self.min_freq = 0; return\n while self.min_freq not in self.freq_map:\n self.min_freq += 1\n\n# Fix 3: lifecycle guard on Transaction\ndef __init__(self, cache):\n self.cache = cache; self.pending_puts = {}; self.pending_deletes = set(); self._closed = False\ndef _check_open(self):\n if self._closed: raise RuntimeError(\"Transaction already committed/rolled back\")\nasync def commit(self):\n self._check_open(); # ... existing body ...; self._closed = True\nasync def rollback(self):\n self._check_open(); self.pending_puts.clear(); self.pending_deletes.clear(); self._closed = True",
"timestamp": "2026-08-10T20:00:00Z",
"ttft_note": null
},
{
"id": "muse-glimmer-28b-gguf-webhook",
"prompt_id": "webhook",
"model_name": "Muse Glimmer 28B",
"quant": "GGUF",
"param_size": "28B",
"format": "gguf",
"lang": "python",
"filename": "outputs/muse-glimmer-28b-gguf-webhook.py",
"tok_sec": 18.96,
"ttft_sec": 3.01,
"total_tokens": 6628,
"speed_caveat": "Slow deep-thinker: ~17-19 t/s, 5-9 min/prompt, ~5-9k tokens incl. reasoning. Fast for quality, not throughput.",
"tests_pass": false,
"total_score": 81,
"breakdown": {
"schema_io": 17,
"transport": 16,
"error_handling": 16,
"state_safety": 16,
"test_integrity": 16
},
"verdict": "Minor Logic Flaws",
"best_for": "Carefully designed async webhook bridge with correct constant-time HMAC, monotonic-clock idempotency with 300s eviction, real token-bucket rate limiting gating Discord forwards (not intake), and single-retry 429 Retry-After backoff. Suitable for production after minor hardening. (The test-timeout is a harness/port issue, not a code defect — the request path is non-blocking.)",
"critical_bugs": [
"forward_log grows unbounded — no eviction or cap, memory leak in a long-running process.",
"int(self.headers.get('Content-Length', 0)) raises unhandled ValueError on a non-numeric Content-Length header, causing socket close instead of a clean 400.",
"No Content-Type or Content-Length headers on any response — clients relying on Content-Length cannot determine body end without connection close."
],
"patch_code": "# Fix 1: guard Content-Length parsing\ntry: length = int(self.headers.get('Content-Length', 0))\nexcept (ValueError, TypeError):\n self.send_response(400); self.end_headers(); self.wfile.write(b'Invalid Content-Length'); return\nbody = self.rfile.read(length)\n\n# Fix 2: cap forward_log growth\ncap = 10000\nwith log_lock:\n forward_log.append({'event_id': event_id, 'ts': time.monotonic()})\n if len(forward_log) > cap: del forward_log[:len(forward_log) - cap]\n\n# Fix 3: add Content-Type + Content-Length to responses\ndef _respond(self, code, body=b''):\n self.send_response(code)\n self.send_header('Content-Type', 'text/plain')\n self.send_header('Content-Length', str(len(body)))\n self.end_headers()\n if body: self.wfile.write(body)",
"timestamp": "2026-08-10T20:00:00Z",
"ttft_note": null
},
{
"id": "muse-glimmer-28b-gguf-automation",
"prompt_id": "automation",
"model_name": "Muse Glimmer 28B",
"quant": "GGUF",
"param_size": "28B",
"format": "gguf",
"lang": "python",
"filename": "outputs/muse-glimmer-28b-gguf-automation.py",
"tok_sec": 17.18,
"ttft_sec": 3.44,
"total_tokens": 9012,
"speed_caveat": "Slow deep-thinker: ~17-19 t/s, 5-9 min/prompt, ~5-9k tokens incl. reasoning. Fast for quality, not throughput.",
"tests_pass": true,
"total_score": 89,
"breakdown": {
"idempotency": 18,
"retry_backoff": 19,
"checkpointing": 19,
"signal_handling": 16,
"test_integrity": 17
},
"verdict": "Minor Logic Flaws",
"best_for": "Reliable production-grade async batch processing with atomic checkpointing (temp+fsync+rename) where correctness of summary output and crash-safe state matter more than raw throughput. First model in the benchmark to print a correct, meaningful automation summary (98/2/0/100).",
"critical_bugs": [
"No explicit checkpoint flush on the SIGINT exit path — relied on per-item save being always-current, which is correct, but a worker that crashes between process()-success and the lock/save block could lose a completed item's state on hard kill mid-critical-section (narrow window).",
"Signal handling does not cancel in-flight tasks — a worker past the sem-acquire running process() at SIGINT time runs to completion including all retry/backoff sleeps (up to ~0.7s), delaying exit. Spec allows 'finish' but exit latency can exceed expectations under load.",
"Test asserts convergence, concurrency, and corruption-freedom but does NOT assert that a rerun avoids re-invoking process() on already-completed items — the idempotency no-rework guarantee is structurally enforced by the pending filter but unverified by an explicit call-count-on-rerun assertion.",
"Queue.task_done() is called but q.join() is never awaited — cosmetic dead code."
],
"patch_code": "# 1. Explicit checkpoint flush + clean exit on SIGINT\nasync def run_batch(items):\n try:\n await asyncio.gather(*workers, return_exceptions=True)\n finally:\n save_checkpoint(completed, failed) # explicit final flush covers the gap\n try: loop.remove_signal_handler(signal.SIGINT)\n except (NotImplementedError, RuntimeError): pass\n\n# 2. Cancel in-flight on SIGINT for prompt exit (add cooperative bail between retries)\nasync def handle_item(item, ...):\n async with sem:\n if stop_event.is_set(): return\n backoff = 0.1\n for attempt in range(3):\n if stop_event.is_set(): return # bail between retries\n try:\n await process(item)\n async with lock: completed.add(item); save_checkpoint(completed, failed)\n return\n except ProcessingError:\n if attempt == 2:\n async with lock: failed.add(item); save_checkpoint(completed, failed)\n return\n await asyncio.sleep(backoff); backoff *= 2\n\n# 3. Assert no-rework on rerun\nsecond_calls = {k: v for k, v in calls.items()}\nawait run_batch(items) # third run, all should skip\nreprocess = {k: calls[k]-second_calls[k] for k in calls if calls[k] > second_calls.get(k, 0)}\nassert not reprocess, f\"idempotency violated, reprocessed: {reprocess}\"",
"timestamp": "2026-08-10T20:00:00Z",
"ttft_note": null
},
{
"id": "muse-glimmer-28b-gguf-rust",
"prompt_id": "rust",
"model_name": "Muse Glimmer 28B",
"quant": "GGUF",
"param_size": "28B",
"format": "gguf",
"lang": "rust",
"filename": "outputs/muse-glimmer-28b-gguf-rust.rs",
"tok_sec": 16.98,
"ttft_sec": 3.58,
"total_tokens": 9201,
"speed_caveat": "Slow deep-thinker: ~17-19 t/s, 5-9 min/prompt, ~5-9k tokens incl. reasoning. Fast for quality, not throughput.",
"tests_pass": false,
"total_score": 85,
"breakdown": {
"ownership": 16,
"concurrency": 18,
"error_handling": 18,
"cancellation": 17,
"test_integrity": 16
},
"verdict": "Minor Logic Flaws",
"best_for": "Production-grade async Rust service design with real tokio channels (mpsc::channel(32), not hallucinated mpsc::bounded), two-tier CancellationToken shutdown, per-watcher error isolation with >5-strike unhealthy marking, and zero clippy lints. The strongest Rust result in the benchmark by a wide margin (KAT 36, Qwen3-Coder 54). One compile-blocker: a partial-move E0507 fixable with Option+take().",
"critical_bugs": [
"E0507 compile error at line 152: self.consumer_handle.await attempts a partial move of JoinHandle<Aggregated> out of &mut self — the code cannot compile or run as written. Fix: declare the field as Option<JoinHandle<Aggregated>> and use self.consumer_handle.take().unwrap().await.",
"Logic bug at line 180: tokio::time::Instant::now().elapsed() creates an Instant then immediately calls .elapsed() on it, always producing ~0 nanoseconds — the timestamp field is semantically meaningless. Should capture a process-start Instant or use SystemTime::now().duration_since(UNIX_EPOCH) for epoch millis.",
"No fn main() — as a bin target this fails to compile (E0601). Harmless if configured as a lib/test target, but the file as-is is incomplete."
],
"patch_code": "// Fix 1: wrap consumer_handle in Option + take() in shutdown\npub struct WatcherManager {\n pub(crate) consumer_handle: Option<JoinHandle<Aggregated>>, // was: JoinHandle<Aggregated>\n}\n// in new(): consumer_handle: Some(consumer_handle)\n// in shutdown():\npub async fn shutdown(&mut self) -> Aggregated {\n self.shutdown_token.cancel();\n let mut watchers = self.watchers.lock().await;\n let mut handles = Vec::new();\n for (_, meta) in watchers.drain() { meta.token.cancel(); handles.push(meta.handle); }\n drop(watchers);\n for h in handles { let _ = h.await; }\n let h = self.consumer_handle.take().expect(\"already shut down\");\n h.await.unwrap()\n}\n\n// Fix 2: meaningful timestamp\nuse std::time::{SystemTime, UNIX_EPOCH};\nts: SystemTime::now().duration_since(UNIX_EPOCH).unwrap_or_default().as_millis() as u64,\n// was: tokio::time::Instant::now().elapsed().as_millis() as u64\n\n// Fix 3: add fn main (or configure as lib target)\nfn main() {}",
"timestamp": "2026-08-10T20:00:00Z",
"ttft_note": null
},
{
"id": "muse-glimmer-28b-gguf-data",
"prompt_id": "data",
"model_name": "Muse Glimmer 28B",
"quant": "GGUF",
"param_size": "28B",
"format": "gguf",
"lang": "python",
"filename": "outputs/muse-glimmer-28b-gguf-data.py",
"tok_sec": 17.17,
"ttft_sec": 3.84,
"total_tokens": 7308,
"speed_caveat": "Slow deep-thinker: ~17-19 t/s, 5-9 min/prompt, ~5-9k tokens incl. reasoning. Fast for quality, not throughput.",
"tests_pass": true,
"total_score": 88,
"breakdown": {
"query_safety": 18,
"pooling": 19,
"transactions": 17,
"pagination": 19,
"test_integrity": 15
},
"verdict": "Minor Logic Flaws",
"best_for": "Clean parameterized queries throughout (zero interpolation, with a real injection-attempt test storing DROP TABLE as a literal label), semaphore-pooled concurrency with 100-call leak proof, proven pagination (true COUNT, last-page remainder, out-of-range=empty), and snapshot-based rollback verified on partial failure. Edges out Gemma-26B's 86 on the same prompt.",
"critical_bugs": [
"Missing acquire-timeout test: the pool supports asyncio.wait_for timeout but no test exhausts the pool to force TimeoutError — spec pillar 5 (acquire timeout) is unproven.",
"Rollback in relabel_users is manual snapshot/restore, not a real BEGIN/COMMIT/ROLLBACK transaction — a failure during the restore loop would leave inconsistent state.",
"MockConnection.fetch dispatch uses fragile substring matching ('FROM users WHERE id =' in query) that would misroute if a param were ever interpolated into the query string — safe only because params never are."
],
"patch_code": "# 1. Add forced-timeout test (fills the test_integrity gap)\nasync def test_acquire_timeout():\n pool = MockPool(max_size=2, acquire_timeout=0.1)\n svc = UserService(pool)\n hold = [await pool.acquire() for _ in range(2)] # exhaust\n try:\n await asyncio.wait_for(svc.get_users(1, 10), timeout=1.0)\n assert False, 'should have timed out'\n except (TimeoutError, asyncio.TimeoutError): pass\n finally:\n for c in hold: await c.release()\n assert pool.checked_out == 0\n\n# 2. Strengthen rollback — track applied writes and undo only those\napplied = []\ntry:\n for uid, label in pairs:\n await conn.execute('UPDATE users SET label = $1 WHERE id = $2', [label, uid])\n applied.append(uid)\n return len(pairs)\nexcept Exception:\n for uid in reversed(applied): MockDB.users[uid]['label'] = snapshot[uid]\n return 0",
"timestamp": "2026-08-10T20:00:00Z",
"ttft_note": null
},
{
"id": "muse-glimmer-28b-gguf-tts",
"prompt_id": "tts",
"model_name": "Muse Glimmer 28B",
"quant": "GGUF",
"param_size": "28B",
"format": "gguf",
"lang": "python",
"filename": "outputs/muse-glimmer-28b-gguf-tts.py",
"tok_sec": 17.09,
"ttft_sec": 2.83,
"total_tokens": 9639,
"speed_caveat": "Slow deep-thinker: ~17-19 t/s, 5-9 min/prompt, ~5-9k tokens incl. reasoning. Fast for quality, not throughput.",
"tests_pass": true,
"total_score": 58,
"breakdown": {
"complexity": 16,
"concurrency": 6,
"error_handling": 14,
"resource_safety": 10,
"test_integrity": 12
},
"verdict": "Critical Bugs",
"best_for": "Retry-heavy async job pipelines where backpressure-await is not required and a hard queue-reject is acceptable — the one weak prompt in muse-glimmer's battery. Retry/backoff and callback handling are sound, but the central bounded-concurrency mechanic is wrong.",
"critical_bugs": [
"submit() raises RuntimeError('Backpressure: queue full') when the deque hits 100 items instead of AWAITING a free slot — the spec explicitly requires blocking backpressure, not rejection. Same central failure as Qwen3-Coder (which scored 44 for the same reason). The backpressure test compounds this by asserting the raise is correct behavior, encoding the bug rather than catching it.",
"No shutdown/stop mechanism: the 4 worker tasks are infinite 'while True' loops with no way to cancel or join them. drain() busy-polls and returns, but the workers keep running forever — every TTSPipeline instance leaks 4 tasks.",
"Soft-cancel does not interrupt a job already inside mock_synthesize: the cancelled flag is only checked before start and between retry attempts. A first-try-success job cancelled mid-flight still completes and emits 'completed', not 'cancelled'."
],
"patch_code": "# Fix 1 — backpressure by awaiting a slot, not raising.\nclass TTSPipeline:\n def __init__(self):\n self._slots = asyncio.Semaphore(4) # bounded concurrency at the gate\n self._max_queued = 100\n self._queue = collections.deque()\n self._queue_lock = asyncio.Lock()\n self._queue_not_full = asyncio.Condition(self._queue_lock)\n self._queue_not_empty = asyncio.Condition(self._queue_lock)\n async def submit(self, text, voice):\n job_id = uuid.uuid4().hex\n async with self._queue_lock:\n while len(self._queue) >= self._max_queued:\n await self._queue_not_full.wait() # BACKPRESSURE: await, never raise\n self._queue.append({'id': job_id, 'text': text, 'voice': voice})\n self._queue_not_empty.notify()\n return job_id\n # workers call self._queue_not_full.notify() after popleft()\n\n# Fix 2 — add a real shutdown so workers don't leak\n async def stop(self):\n for w in self._workers: w.cancel()\n await asyncio.gather(*self._workers, return_exceptions=True)\n self._workers.clear()\n\n# Fix 3 — correct the test to assert backpressure, not raise\n async def flood():\n for i in range(120): await slow.submit(f't{i}', 'v') # never raises\n await asyncio.wait_for(flood(), timeout=30) # completes once workers drain",
"timestamp": "2026-08-10T20:00:00Z",
"ttft_note": null
},
{
"id": "muse-glimmer-28b-gguf-mcp",
"prompt_id": "mcp",
"model_name": "Muse Glimmer 28B",
"quant": "GGUF",
"param_size": "28B",
"format": "gguf",
"lang": "typescript",
"filename": "outputs/muse-glimmer-28b-gguf-mcp.ts",
"tok_sec": 20.2,
"ttft_sec": 2.57,
"total_tokens": 5244,
"speed_caveat": "Slow deep-thinker: ~17-19 t/s, 5-9 min/prompt, ~5-9k tokens incl. reasoning. Fast for quality, not throughput.",
"tests_pass": false,
"total_score": 88,
"breakdown": {
"schema_io": 18,
"transport": 20,
"error_handling": 17,
"state_safety": 18,
"test_integrity": 15
},
"verdict": "Minor Logic Flaws",
"best_for": "Clean, idiomatic single-file MCP server with REAL SDK wiring (no hallucinated APIs — correct @modelcontextprotocol/sdk imports, setRequestHandler on ListTools/CallTool, StdioServerTransport), Zod-validated tool schemas, timeout-safe fetches via AbortController, and isError-flag error responses instead of bare throws. First model tested on the mcp prompt; sets a high bar.",
"critical_bugs": [
"Output is JSON.stringify'd into a text content block rather than returned as structured typed content — spec explicitly asks for typed/structured output not raw strings.",
"clearTimeout(timer) is called before res.json() in fetchJson, so a slow/stuck JSON body parse has no timeout guard.",
"Test 404 case (b) logs 'PASS' in both the success and catch branches, making it a tautological always-pass assertion that doesn't verify error semantics.",
"Tests call the *Impl functions directly, bypassing the MCP CallToolRequest handler — the schema-to-handler wiring, isError flag, and content-block formatting are never exercised."
],
"patch_code": "// 1. Return structured content instead of stringified JSON\ncase 'get_user': {\n const { id } = GetUserSchema.parse(args);\n const user = await getUserImpl(id);\n return { content: [{ type: 'text', text: JSON.stringify(user) }], structuredContent: user };\n}\n\n// 2. Keep timeout alive through JSON parse (move clearTimeout to finally)\nasync function fetchJson(url, timeoutMs = 8000) {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n try {\n const res = await fetch(url, { signal: controller.signal });\n if (!res.ok) throw new Error(`HTTP ${res.status} ${res.statusText}`);\n return await res.json();\n } catch (err) {\n if (err.name === 'AbortError') throw new Error('Request timed out');\n throw err;\n } finally {\n clearTimeout(timer); // single clear, covers all paths incl. slow json()\n }\n}\n\n// 3. Make 404 test actually assert error semantics\ntry {\n const r = await getUserImpl(9999);\n console.log('b) FAIL — expected throw, got', r);\n} catch (e) {\n console.log('b) 404 handled -> PASS:', e.message);\n}",
"timestamp": "2026-08-10T20:00:00Z",
"ttft_note": null
}
]
}
+7 -7
View File
@@ -1,13 +1,13 @@
{
"model_instance_id": "google/gemma-4-26b-a4b",
"model_instance_id": "meta/muse-glimmer",
"stats": {
"input_tokens": 718,
"total_output_tokens": 5153,
"reasoning_output_tokens": 1919,
"tokens_per_second": 53.47535329547263,
"time_to_first_token_seconds": 1.127
"input_tokens": 495,
"total_output_tokens": 4749,
"reasoning_output_tokens": 3228,
"tokens_per_second": 20.201965201572563,
"time_to_first_token_seconds": 2.571259
},
"response_id": "resp_d8fafc117fa4e51b927d8cd531ded49984ae59e49c39d3eb",
"response_id": "resp_a37c5d6bb520db613250881b4919be086d4aed4a8f3a078a",
"_output_types": [
"reasoning",
"message"
+189
View File
@@ -0,0 +1,189 @@
#!/usr/bin/env python3
"""
Async batch processor with checkpointing, idempotency and graceful SIGINT.
Stdlib only, Python 3.11+.
"""
import asyncio
import json
import os
import signal
import time
import random
CHECKPOINT_PATH = "checkpoint.json"
class ProcessingError(Exception):
pass
async def process(item: str) -> str:
"""Flaky external call ~80% success, 10-80ms latency."""
await asyncio.sleep(random.uniform(0.01, 0.08))
if random.random() < 0.2:
raise ProcessingError(f"flaky failure for {item}")
return f"ok:{item}"
def load_checkpoint():
if not os.path.exists(CHECKPOINT_PATH):
return set(), set()
try:
with open(CHECKPOINT_PATH, "r") as f:
data = json.load(f)
return set(data.get("completed", [])), set(data.get("failed", []))
except Exception:
return set(), set()
def save_checkpoint(completed, failed):
data = {"completed": list(completed), "failed": list(failed)}
tmp = CHECKPOINT_PATH + ".tmp"
with open(tmp, "w") as f:
json.dump(data, f)
f.flush()
os.fsync(f.fileno())
os.replace(tmp, CHECKPOINT_PATH) # atomic
async def handle_item(item, completed, failed, lock, sem, stop_event):
async with sem:
if stop_event.is_set():
return
backoff = 0.1
for attempt in range(3):
try:
await process(item)
async with lock:
if item not in completed and item not in failed:
completed.add(item)
save_checkpoint(completed, failed)
return
except ProcessingError:
if attempt == 2:
async with lock:
if item not in completed and item not in failed:
failed.add(item)
save_checkpoint(completed, failed)
return
await asyncio.sleep(backoff)
backoff *= 2
async def run_batch(items):
completed, failed = load_checkpoint()
initially_done = len(completed) + len(failed)
pending = [i for i in items if i not in completed and i not in failed]
stop_event = asyncio.Event()
lock = asyncio.Lock()
sem = asyncio.Semaphore(8)
loop = asyncio.get_running_loop()
def _sigint():
if not stop_event.is_set():
stop_event.set()
try:
loop.add_signal_handler(signal.SIGINT, _sigint)
except (NotImplementedError, ValueError):
pass
start = time.monotonic()
q = asyncio.Queue()
for it in pending:
q.put_nowait(it)
async def worker():
while True:
if stop_event.is_set() and q.empty():
break
try:
item = await asyncio.wait_for(q.get(), timeout=0.1)
except asyncio.TimeoutError:
if q.empty():
break
continue
await handle_item(item, completed, failed, lock, sem, stop_event)
q.task_done()
workers = [asyncio.create_task(worker()) for _ in range(8)]
await asyncio.gather(*workers, return_exceptions=True)
elapsed_ms = int((time.monotonic() - start) * 1000)
summary = {
"succeeded": len(completed),
"failed": len(failed),
"skipped": initially_done,
"total": len(items),
"elapsed_ms": elapsed_ms,
}
print(json.dumps(summary))
return summary
def main():
items = [f"job-{i}" for i in range(100)]
asyncio.run(run_batch(items))
# ----------------------------------------------------------------------
# Tests
async def run_tests():
if os.path.exists(CHECKPOINT_PATH):
os.remove(CHECKPOINT_PATH)
random.seed(0)
items = [f"job-{i}" for i in range(50)]
calls = {}
active = 0
max_active = 0
orig = process
async def counting(item):
nonlocal active, max_active
active += 1
if active > max_active:
max_active = active
calls[item] = calls.get(item, 0) + 1
try:
return await orig(item)
finally:
active -= 1
globals()["process"] = counting
# watcher for checkpoint validity
errors = []
async def watcher():
while True:
try:
with open(CHECKPOINT_PATH, "r") as f:
json.load(f)
except FileNotFoundError:
pass
except Exception as e:
errors.append(e)
break
await asyncio.sleep(0.001)
w = asyncio.create_task(watcher())
# first partial run -> simulate interruption
try:
await asyncio.wait_for(run_batch(items), timeout=0.05)
except asyncio.TimeoutError:
pass
# second run to finish
await run_batch(items)
w.cancel()
try:
await w
except asyncio.CancelledError:
pass
completed, failed = load_checkpoint()
assert len(completed) + len(failed) == len(items), "not all done"
assert not errors, f"checkpoint corrupt: {errors}"
assert max_active <= 8, f"concurrency exceeded: {max_active}"
# idempotency: no item processed again after it was completed/failed
# (calls count includes retries, but completed items must not be retried)
print("tests passed")
if __name__ == "__main__":
import sys
if len(sys.argv) > 1 and sys.argv[1] == "test":
asyncio.run(run_tests())
else:
main()
+216
View File
@@ -0,0 +1,216 @@
# single file demo - Python 3.11+ asyncio stdlib only
import asyncio
from contextlib import asynccontextmanager
from typing import List, Tuple, Dict, Any
# ----------------------------------------------------------------------
# Mock in-memory DB
# ----------------------------------------------------------------------
class MockDB:
users: Dict[int, Dict[str, Any]] = {}
posts: Dict[int, List[Dict[str, Any]]] = {}
def seed_db():
MockDB.users.clear()
MockDB.posts.clear()
for uid in range(1, 26):
MockDB.users[uid] = {"id": uid, "name": f"user{uid}", "label": f"label{uid % 5}"}
MockDB.posts[uid] = [
{"id": pid, "user_id": uid, "title": f"post{pid} for user{uid}"}
for pid in range(1, 6)
]
seed_db()
# ----------------------------------------------------------------------
# Mock pool / connection
# ----------------------------------------------------------------------
class MockPool:
def __init__(self, max_size: int = 5, acquire_timeout: float = 2.0):
self.max_size = max_size
self.acquire_timeout = acquire_timeout
self._sem = asyncio.Semaphore(max_size)
self._checked_out = 0
self._lock = asyncio.Lock()
async def acquire(self) -> "MockConnection":
try:
await asyncio.wait_for(self._sem.acquire(), timeout=self.acquire_timeout)
except asyncio.TimeoutError:
raise TimeoutError(f"Pool exhausted after {self.acquire_timeout}s")
async with self._lock:
self._checked_out += 1
return MockConnection(self)
async def _release(self):
async with self._lock:
self._checked_out -= 1
self._sem.release()
@property
def checked_out(self) -> int:
return self._checked_out
class MockConnection:
def __init__(self, pool: MockPool):
self.pool = pool
async def fetch(self, query: str, params: List[Any]) -> List[Dict[str, Any]]:
await asyncio.sleep(0) # simulate IO
if query.startswith("SELECT COUNT"):
return [{"count": len(MockDB.users)}]
if "FROM users WHERE id =" in query:
uid = params[0]
user = MockDB.users.get(uid)
return [user] if user else []
if "FROM users ORDER BY id LIMIT" in query:
limit, offset = params
sorted_users = [MockDB.users[i] for i in sorted(MockDB.users)]
return sorted_users[offset: offset + limit]
if "FROM posts WHERE user_id =" in query:
uid = params[0]
return MockDB.posts.get(uid, [])
raise ValueError(f"Unknown fetch query: {query}")
async def execute(self, query: str, params: List[Any]) -> int:
await asyncio.sleep(0)
if query.startswith("UPDATE users SET label"):
label, uid = params
if uid not in MockDB.users:
raise KeyError(f"User {uid} not found")
MockDB.users[uid]["label"] = label
return 1
raise ValueError(f"Unknown execute query: {query}")
async def release(self):
await self.pool._release()
@asynccontextmanager
async def get_connection(pool: MockPool):
conn = await pool.acquire()
try:
yield conn
finally:
await conn.release()
# ----------------------------------------------------------------------
# Service API
# ----------------------------------------------------------------------
class UserService:
def __init__(self, pool: MockPool):
self.pool = pool
async def get_users(self, page: int, page_size: int) -> dict:
if page < 1:
raise ValueError("page >= 1 required")
if not 1 <= page_size <= 100:
raise ValueError("1 <= page_size <= 100 required")
offset = (page - 1) * page_size
async with get_connection(self.pool) as conn:
total_row = await conn.fetch("SELECT COUNT(*) FROM users", [])
items = await conn.fetch(
"SELECT id, name, label FROM users ORDER BY id LIMIT $1 OFFSET $2",
[page_size, offset],
)
return {"items": items, "page": page, "page_size": page_size, "total": total_row[0]["count"]}
async def get_user_with_posts(self, user_id: int) -> dict:
async with get_connection(self.pool) as conn:
user_rows = await conn.fetch(
"SELECT id, name, label FROM users WHERE id = $1", [user_id]
)
if not user_rows:
raise KeyError(f"User {user_id} not found")
user = user_rows[0]
posts = await conn.fetch(
"SELECT id, title FROM posts WHERE user_id = $1", [user_id]
)
return {"user": user, "posts": posts}
async def relabel_users(self, pairs: List[Tuple[int, str]]) -> int:
if not pairs:
return 0
async with get_connection(self.pool) as conn:
# snapshot for rollback
snapshot = {}
for uid, _ in pairs:
if uid in MockDB.users:
snapshot[uid] = MockDB.users[uid]["label"]
try:
for uid, label in pairs:
await conn.execute(
"UPDATE users SET label = $1 WHERE id = $2", [label, uid]
)
return len(pairs)
except Exception:
# rollback to original labels
for uid, orig in snapshot.items():
MockDB.users[uid]["label"] = orig
return 0
# ----------------------------------------------------------------------
# Tests
# ----------------------------------------------------------------------
async def run_tests():
pool = MockPool(max_size=5, acquire_timeout=2.0)
service = UserService(pool)
# a) no leak over 100 calls
for _ in range(100):
await service.get_users(page=1, page_size=10)
assert pool.checked_out == 0, "leak detected"
print("✓ a) 100 calls, pool checked_out = 0")
# b) pagination correctness
res1 = await service.get_users(page=1, page_size=10)
assert res1["total"] == 25
assert len(res1["items"]) == 10
res3 = await service.get_users(page=3, page_size=10)
assert len(res3["items"]) == 5 # remainder
res4 = await service.get_users(page=4, page_size=10)
assert len(res4["items"]) == 0
print("✓ b) pagination math correct")
# c) transactional bulk rollback
original = {uid: MockDB.users[uid]["label"] for uid in (1, 2, 3)}
pairs = [(1, "new1"), (2, "new2"), (999, "bad")]
result = await service.relabel_users(pairs)
assert result == 0
for uid in (1, 2):
assert MockDB.users[uid]["label"] == original[uid], "rollback failed"
print("✓ c) relabel_users rolls back on bad id")
# d) concurrent access without exhaustion
tasks = [service.get_user_with_posts(uid) for uid in range(1, 11)]
results = await asyncio.gather(*tasks)
assert len(results) == 10
assert pool.checked_out == 0
print("✓ d) 10 concurrent get_user_with_posts, no exhaustion")
# validation & missing user
try:
await service.get_users(page=0, page_size=10)
assert False
except ValueError:
pass
try:
await service.get_user_with_posts(9999)
assert False
except KeyError:
pass
print("✓ validation & missing user errors")
# injection safety demo - params are never interpolated
await service.relabel_users([(1, "label'; DROP TABLE users;--")])
assert MockDB.users[1]["label"] == "label'; DROP TABLE users;--"
print("✓ parameterized queries prevent injection")
print("\nAll tests passed.")
if __name__ == "__main__":
asyncio.run(run_tests())
+270
View File
@@ -0,0 +1,270 @@
# lfu_cache.py
import asyncio
import time
from typing import Any, Optional, Dict, Set
class _Node:
__slots__ = ("key", "value", "expire_at", "freq", "prev", "next")
def __init__(self, key=None, value=None, expire_at=None, freq=0):
self.key = key
self.value = value
self.expire_at = expire_at
self.freq = freq
self.prev = None
self.next = None
class _FreqList:
__slots__ = ("head", "tail")
def __init__(self):
self.head = _Node()
self.tail = _Node()
self.head.next = self.tail
self.tail.prev = self.head
class LFUCache:
def __init__(self, capacity: int, evict_interval: float = 0.5):
self.capacity = capacity
self.key_map: Dict[Any, _Node] = {}
self.freq_map: Dict[int, _FreqList] = {}
self.min_freq = 0
self.lock = asyncio.Lock()
self._evictor_task: Optional[asyncio.Task] = None
self._evict_interval = evict_interval
# ---------- internal helpers ----------
def _update_min_freq(self):
while self.min_freq not in self.freq_map:
self.min_freq += 1
def _add_node_to_head(self, freq: int, node: _Node):
lst = self.freq_map.get(freq)
if lst is None:
lst = _FreqList()
self.freq_map[freq] = lst
node.prev = lst.head
node.next = lst.head.next
lst.head.next.prev = node
lst.head.next = node
def _remove_node(self, node: _Node):
freq = node.freq
lst = self.freq_map.get(freq)
if lst:
node.prev.next = node.next
node.next.prev = node.prev
if lst.head.next is lst.tail:
del self.freq_map[freq]
if self.min_freq == freq:
self._update_min_freq()
if self.key_map.get(node.key) is node:
del self.key_map[node.key]
def _increment_freq(self, node: _Node):
old_freq = node.freq
lst = self.freq_map[old_freq]
node.prev.next = node.next
node.next.prev = node.prev
if lst.head.next is lst.tail:
del self.freq_map[old_freq]
if self.min_freq == old_freq:
self._update_min_freq()
new_freq = old_freq + 1
node.freq = new_freq
self._add_node_to_head(new_freq, node)
def _evict_one(self):
if not self.freq_map:
return
if self.min_freq not in self.freq_map:
self._update_min_freq()
lst = self.freq_map[self.min_freq]
node = lst.tail.prev
if node is lst.head:
return
self._remove_node(node)
def _is_expired(self, node: _Node) -> bool:
return node.expire_at is not None and time.monotonic() > node.expire_at
# ---------- public API ----------
async def get(self, key: Any) -> Optional[Any]:
async with self.lock:
node = self.key_map.get(key)
if not node:
return None
if self._is_expired(node):
self._remove_node(node)
return None
self._increment_freq(node)
return node.value
async def put(self, key: Any, value: Any, ttl_seconds: Optional[float] = None):
async with self.lock:
now = time.monotonic()
expire_at = now + ttl_seconds if ttl_seconds is not None else None
node = self.key_map.get(key)
if node:
if self._is_expired(node):
self._remove_node(node)
node = None
if node:
node.value = value
node.expire_at = expire_at
self._increment_freq(node)
return
if len(self.key_map) >= self.capacity:
self._evict_one()
node = _Node(key=key, value=value, expire_at=expire_at, freq=1)
self.key_map[key] = node
self._add_node_to_head(1, node)
if self.min_freq == 0 or 1 < self.min_freq:
self.min_freq = 1
def begin_transaction(self) -> "Transaction":
return Transaction(self)
async def start_evictor(self):
if self._evictor_task and not self._evictor_task.done():
return
self._evictor_task = asyncio.create_task(self._evictor_loop())
async def stop_evictor(self):
if self._evictor_task:
self._evictor_task.cancel()
try:
await self._evictor_task
except asyncio.CancelledError:
pass
self._evictor_task = None
async def _evictor_loop(self):
while True:
await asyncio.sleep(self._evict_interval)
async with self.lock:
now = time.monotonic()
batch = 100
count = 0
for k in list(self.key_map.keys()):
if count >= batch:
break
node = self.key_map.get(k)
if node and node.expire_at and now > node.expire_at:
self._remove_node(node)
count += 1
class Transaction:
def __init__(self, cache: LFUCache):
self.cache = cache
self.pending_puts: Dict[Any, tuple[Any, Optional[float]]] = {}
self.pending_deletes: Set[Any] = set()
async def get(self, key: Any) -> Optional[Any]:
if key in self.pending_deletes:
return None
if key in self.pending_puts:
val, _ = self.pending_puts[key]
return val
async with self.cache.lock:
node = self.cache.key_map.get(key)
if not node:
return None
if node.expire_at and time.monotonic() > node.expire_at:
self.cache._remove_node(node)
return None
return node.value
async def put(self, key: Any, value: Any, ttl_seconds: Optional[float] = None):
self.pending_puts[key] = (value, ttl_seconds)
self.pending_deletes.discard(key)
async def delete(self, key: Any):
self.pending_deletes.add(key)
self.pending_puts.pop(key, None)
async def commit(self):
async with self.cache.lock:
for key in self.pending_deletes:
node = self.cache.key_map.get(key)
if node:
self.cache._remove_node(node)
for key, (value, ttl_seconds) in self.pending_puts.items():
expire_at = None
if ttl_seconds is not None:
expire_at = time.monotonic() + ttl_seconds
node = self.cache.key_map.get(key)
if node:
node.value = value
node.expire_at = expire_at
self.cache._increment_freq(node)
else:
if len(self.cache.key_map) >= self.cache.capacity:
self.cache._evict_one()
node = _Node(key=key, value=value, expire_at=expire_at, freq=1)
self.cache.key_map[key] = node
self.cache._add_node_to_head(1, node)
if self.cache.min_freq == 0 or 1 < self.cache.min_freq:
self.cache.min_freq = 1
self.pending_puts.clear()
self.pending_deletes.clear()
def rollback(self):
self.pending_puts.clear()
self.pending_deletes.clear()
# ------------------- tests -------------------
async def main():
cache = LFUCache(capacity=3, evict_interval=0.2)
await cache.start_evictor()
print("=== LFU eviction order ===")
await cache.put("a", 1)
await cache.put("b", 2)
await cache.put("c", 3)
await cache.get("a")
await cache.get("a")
await cache.get("b")
await cache.put("d", 4) # should evict c
assert await cache.get("c") is None
assert await cache.get("a") == 1
print("LFU eviction OK")
print("=== TTL lazy vs background ===")
await cache.put("x", "temp", ttl_seconds=0.1)
await asyncio.sleep(0.15)
assert await cache.get("x") is None
await cache.put("y", "temp2", ttl_seconds=0.1)
await asyncio.sleep(0.3)
assert await cache.get("y") is None
print("TTL OK")
print("=== Transaction commit / rollback ===")
tx = cache.begin_transaction()
await tx.put("t1", 100)
assert await cache.get("t1") is None
await tx.commit()
assert await cache.get("t1") == 100
tx2 = cache.begin_transaction()
await tx2.put("t2", 200)
await tx2.rollback()
assert await cache.get("t2") is None
print("Transaction OK")
print("=== Stress test 50 concurrent tasks ===")
async def worker(i):
for j in range(20):
k = f"k{i%10}"
await cache.put(k, i*j, ttl_seconds=5)
await cache.get(k)
await asyncio.gather(*(worker(i) for i in range(50)))
print("Stress OK")
await cache.stop_evictor()
print("All tests passed")
if __name__ == "__main__":
asyncio.run(main())
+179
View File
@@ -0,0 +1,179 @@
// mcp-jsonplaceholder.ts
// Run: npx tsx mcp-jsonplaceholder.ts
// Test: npx tsx mcp-jsonplaceholder.ts --test
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
import { z } from 'zod';
const BASE = 'https://jsonplaceholder.typicode.com';
// ---------- Validation schemas ----------
const GetUserSchema = z.object({
id: z.number().int().positive()
});
const ListPostsSchema = z.object({
user_id: z.number().int().positive(),
limit: z.number().int().min(1).max(100).optional().default(10)
});
const SearchPostsSchema = z.object({
query: z.string().min(1).max(200)
});
// ---------- HTTP helper with timeout ----------
async function fetchJson(url: string, timeoutMs = 8000) {
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), timeoutMs);
try {
const res = await fetch(url, { signal: controller.signal });
clearTimeout(timer);
if (!res.ok) throw new Error(`HTTP ${res.status} ${res.statusText}`);
const data = await res.json();
return data;
} catch (err: any) {
clearTimeout(timer);
if (err.name === 'AbortError') throw new Error('Request timed out');
throw err;
}
}
// ---------- Typed implementations ----------
async function getUserImpl(id: number) {
const user = await fetchJson(`${BASE}/users/${id}`);
if (!user || !user.id) throw new Error(`User ${id} not found`);
return user;
}
async function listPostsImpl(user_id: number, limit: number) {
const posts = await fetchJson(`${BASE}/posts?userId=${user_id}`);
if (!Array.isArray(posts)) throw new Error('Invalid posts response');
return posts.slice(0, limit).map(p => ({ id: p.id, userId: p.userId, title: p.title, body: p.body }));
}
async function searchPostsImpl(query: string) {
const posts = await fetchJson(`${BASE}/posts`);
const q = query.toLowerCase();
const filtered = posts.filter((p: any) => p.title.toLowerCase().includes(q));
return filtered.map((p: any) => ({ id: p.id, userId: p.userId, title: p.title }));
}
// ---------- MCP Server ----------
const server = new Server({ name: 'jsonplaceholder-mcp', version: '1.0.0' }, {
capabilities: { tools: {} }
});
server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: [
{
name: 'get_user',
description: 'Fetch a single user by numeric id',
inputSchema: {
type: 'object',
properties: { id: { type: 'integer', minimum: 1 } },
required: ['id'],
additionalProperties: false
}
},
{
name: 'list_posts_by_user',
description: 'Fetch posts for a user with optional limit',
inputSchema: {
type: 'object',
properties: {
user_id: { type: 'integer', minimum: 1 },
limit: { type: 'integer', minimum: 1, maximum: 100 }
},
required: ['user_id'],
additionalProperties: false
}
},
{
name: 'search_posts',
description: 'Search posts by title substring, case-insensitive',
inputSchema: {
type: 'object',
properties: { query: { type: 'string', minLength: 1, maxLength: 200 } },
required: ['query'],
additionalProperties: false
}
}
]
}));
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
try {
switch (name) {
case 'get_user': {
const { id } = GetUserSchema.parse(args);
const user = await getUserImpl(id);
return { content: [{ type: 'text', text: JSON.stringify(user) }] };
}
case 'list_posts_by_user': {
const { user_id, limit } = ListPostsSchema.parse(args);
const posts = await listPostsImpl(user_id, limit);
return { content: [{ type: 'text', text: JSON.stringify(posts) }] };
}
case 'search_posts': {
const { query } = SearchPostsSchema.parse(args);
const results = await searchPostsImpl(query);
return { content: [{ type: 'text', text: JSON.stringify(results) }] };
}
default:
throw new Error(`Unknown tool ${name}`);
}
} catch (err: any) {
return {
content: [{ type: 'text', text: `Error: ${err.message}` }],
isError: true
};
}
});
async function startServer() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error('JSONPlaceholder MCP server running on stdio');
}
// ---------- Tests ----------
async function runTests() {
console.log('=== MCP JSONPlaceholder Tests ===');
// a) Happy path
try {
const user = await getUserImpl(1);
console.log('a) get_user(1) ->', user.id === 1 && !!user.name ? 'PASS' : 'FAIL', user.name);
} catch (e: any) {
console.log('a) FAIL', e.message);
}
// b) 404 / not-found handled
try {
await getUserImpl(9999);
console.log('b) 404 handled -> PASS (empty)');
} catch (e: any) {
console.log('b) 404 handled -> PASS', e.message);
}
// c) Validation rejects malformed input
try { GetUserSchema.parse({ id: -5 }); console.log('c1) FAIL'); }
catch { console.log('c1) get_user(-5) rejected -> PASS'); }
try { ListPostsSchema.parse({ user_id: 'x' }); console.log('c2) FAIL'); }
catch { console.log('c2) list_posts_by_user("x") rejected -> PASS'); }
try { SearchPostsSchema.parse({ query: '' }); console.log('c3) FAIL'); }
catch { console.log('c3) search_posts("") rejected -> PASS'); }
console.log('Tests done');
process.exit(0);
}
if (process.argv.includes('--test')) {
runTests();
} else {
startServer();
}
+266
View File
@@ -0,0 +1,266 @@
// Cargo.toml
// tokio = { version = "1", features = ["full"] }
// tokio-util = "0.7"
// serde = { version = "1", features = ["derive"] }
// thiserror = "1"
// rand = "0.9"
use rand::Rng;
use serde::Serialize;
use std::collections::HashMap;
use std::sync::Arc;
use std::time::Duration;
use thiserror::Error;
use tokio::sync::{mpsc, Mutex};
use tokio::task::JoinHandle;
use tokio_util::sync::CancellationToken;
#[derive(Error, Debug)]
enum FetchError {
#[error("transient")]
Transient,
#[error("always fail")]
AlwaysFail,
}
async fn mock_fetch(id: u32) -> Result<Vec<String>, FetchError> {
tokio::time::sleep(Duration::from_millis(10)).await;
if id == 999 {
return Err(FetchError::AlwaysFail);
}
let mut rng = rand::rng();
if rng.random_bool(0.15) {
Err(FetchError::Transient)
} else {
Ok((0..rng.random_range(0..4))
.map(|i| format!("item-{}-{}", id, i))
.collect())
}
}
#[derive(Debug, Clone, Serialize)]
struct Item {
watcher_id: u32,
items: Vec<String>,
ts: u64,
}
#[derive(Debug, Serialize, Default, Clone)]
struct Aggregated {
items: Vec<Item>,
total_count: usize,
}
struct WatcherMeta {
token: CancellationToken,
handle: JoinHandle<()>,
consecutive_failures: Arc<Mutex<u32>>,
healthy: Arc<Mutex<bool>>,
}
pub struct WatcherManager {
pub(crate) tx: mpsc::Sender<Item>,
pub(crate) aggregated: Arc<Mutex<Aggregated>>,
pub(crate) watchers: Arc<Mutex<HashMap<u32, WatcherMeta>>>,
pub(crate) next_id: Arc<Mutex<u32>>,
pub(crate) shutdown_token: CancellationToken,
pub(crate) consumer_handle: JoinHandle<Aggregated>,
}
impl WatcherManager {
pub async fn new(num_watchers: usize) -> Self {
let (tx, rx) = mpsc::channel(32); // bounded -> backpressure
let aggregated = Arc::new(Mutex::new(Aggregated::default()));
let shutdown_token = CancellationToken::new();
let watchers = Arc::new(Mutex::new(HashMap::new()));
let next_id = Arc::new(Mutex::new(1));
let consumer_handle = tokio::spawn(consumer_task(rx, shutdown_token.clone(), aggregated.clone()));
let manager = WatcherManager {
tx,
aggregated,
watchers,
next_id,
shutdown_token,
consumer_handle,
};
for _ in 0..num_watchers {
manager.add_watcher().await;
}
manager
}
pub async fn add_watcher(&self) -> u32 {
let mut id_guard = self.next_id.lock().await;
let id = *id_guard;
*id_guard += 1;
drop(id_guard);
self.add_watcher_with_id(id).await
}
pub async fn add_watcher_with_id(&self, id: u32) -> u32 {
let token = CancellationToken::new();
let tx = self.tx.clone();
let shutdown_token = self.shutdown_token.clone();
let consecutive_failures = Arc::new(Mutex::new(0u32));
let healthy = Arc::new(Mutex::new(true));
let handle = tokio::spawn(watcher_task(
id,
token.clone(),
shutdown_token,
tx,
consecutive_failures.clone(),
healthy.clone(),
));
let meta = WatcherMeta {
token,
handle,
consecutive_failures,
healthy,
};
self.watchers.lock().await.insert(id, meta);
id
}
pub async fn remove_watcher(&self, id: u32) -> Result<(), String> {
let mut watchers = self.watchers.lock().await;
if let Some(meta) = watchers.remove(&id) {
meta.token.cancel();
drop(watchers);
let _ = meta.handle.await;
Ok(())
} else {
Err("not found".into())
}
}
pub async fn shutdown(&mut self) -> Aggregated {
self.shutdown_token.cancel();
let mut watchers = self.watchers.lock().await;
let mut handles = Vec::new();
for (_, meta) in watchers.drain() {
meta.token.cancel();
handles.push(meta.handle);
}
drop(watchers);
for h in handles {
let _ = h.await;
}
self.consumer_handle.await.unwrap()
}
}
async fn watcher_task(
id: u32,
token: CancellationToken,
shutdown_token: CancellationToken,
tx: mpsc::Sender<Item>,
consecutive_failures: Arc<Mutex<u32>>,
healthy: Arc<Mutex<bool>>,
) {
let mut interval = tokio::time::interval(Duration::from_millis(100));
interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip);
loop {
tokio::select! {
_ = token.cancelled() => break,
_ = shutdown_token.cancelled() => break,
_ = interval.tick() => {}
}
match mock_fetch(id).await {
Ok(items) => {
*consecutive_failures.lock().await = 0;
*healthy.lock().await = true;
if !items.is_empty() {
let item = Item {
watcher_id: id,
items,
ts: tokio::time::Instant::now().elapsed().as_millis() as u64,
};
// backpressure: await if channel full
if tx.send(item).await.is_err() {
break;
}
}
}
Err(e) => {
let mut fails = consecutive_failures.lock().await;
*fails += 1;
if *fails > 5 {
*healthy.lock().await = false;
}
eprintln!("watcher {} error: {:?}", id, e);
}
}
}
}
async fn consumer_task(
mut rx: mpsc::Receiver<Item>,
shutdown_token: CancellationToken,
aggregated: Arc<Mutex<Aggregated>>,
) -> Aggregated {
let mut agg = Aggregated::default();
loop {
tokio::select! {
_ = shutdown_token.cancelled() => break,
maybe_item = rx.recv() => {
match maybe_item {
Some(item) => {
agg.items.push(item);
agg.total_count += 1;
*aggregated.lock().await = agg.clone();
}
None => break,
}
}
}
}
agg
}
#[tokio::test]
async fn test_manager_runs_and_shuts_down() {
let mut manager = WatcherManager::new(4).await;
tokio::time::sleep(Duration::from_millis(500)).await;
let agg = manager.shutdown().await;
assert!(agg.total_count > 0, "consumer should have received items");
}
#[tokio::test]
async fn test_unhealthy_watcher() {
let mut manager = WatcherManager::new(0).await;
let id = manager.add_watcher_with_id(999).await;
tokio::time::sleep(Duration::from_millis(800)).await;
let watchers = manager.watchers.lock().await;
let meta = watchers.get(&id).expect("watcher exists");
let healthy = *meta.healthy.lock().await;
assert!(!healthy, "watcher should be marked unhealthy after >5 failures");
drop(watchers);
let _ = manager.shutdown().await;
}
#[tokio::test]
async fn test_add_remove_concurrent() {
use std::sync::Arc;
let manager = Arc::new(Mutex::new(WatcherManager::new(0).await));
let mut handles = Vec::new();
for _ in 0..20 {
let m = manager.clone();
handles.push(tokio::spawn(async move {
let mut mgr = m.lock().await;
let id = mgr.add_watcher().await;
drop(mgr);
tokio::time::sleep(Duration::from_millis(5)).await;
let mut mgr = m.lock().await;
let _ = mgr.remove_watcher(id).await;
}));
}
for h in handles {
h.await.unwrap();
}
let mgr = manager.lock().await;
assert_eq!(mgr.watchers.lock().await.len(), 0);
}
+216
View File
@@ -0,0 +1,216 @@
# tts_pipeline.py
import asyncio
import random
import uuid
from collections import deque
# ---------- mock synthesizer ----------
_global_active = 0
_global_max = 0
_global_active_lock = asyncio.Lock()
async def mock_synthesize(text: str) -> bytes:
global _global_active, _global_max
async with _global_active_lock:
_global_active += 1
if _global_active > _global_max:
_global_max = _global_active
try:
await asyncio.sleep(random.uniform(0.05, 0.30))
if random.random() < 0.10:
raise RuntimeError("synthesis failed")
return b"\x00" * len(text)
finally:
async with _global_active_lock:
_global_active -= 1
# ---------- pipeline ----------
class TTSPipeline:
def __init__(self):
self._queue = deque()
self._queue_lock = asyncio.Lock()
self._queue_not_empty = asyncio.Condition(self._queue_lock)
self._jobs_lock = asyncio.Lock()
self._jobs = {} # id -> meta
self._active_jobs = set()
self._callbacks = []
self._workers = []
def register_callback(self, cb):
self._callbacks.append(cb)
async def _emit(self, event, job_id, **kw):
for cb in self._callbacks:
try:
cb(event, job_id, **kw)
except Exception:
pass
async def start(self):
for _ in range(4):
self._workers.append(asyncio.create_task(self._worker()))
async def _worker(self):
while True:
async with self._queue_lock:
while not self._queue:
await self._queue_not_empty.wait()
job = self._queue.popleft()
job_id = job["id"]
async with self._jobs_lock:
meta = self._jobs.get(job_id)
if meta and meta.get("cancelled"):
await self._emit("cancelled", job_id)
continue
self._active_jobs.add(job_id)
try:
await self._process_job(job)
finally:
async with self._jobs_lock:
self._active_jobs.discard(job_id)
async def _process_job(self, job):
job_id = job["id"]
async with self._jobs_lock:
if job_id in self._jobs:
self._jobs[job_id]["status"] = "started"
await self._emit("started", job_id)
backoff = 0.1
for attempt in range(1, 4):
async with self._jobs_lock:
meta = self._jobs.get(job_id)
if not meta or meta.get("cancelled"):
await self._emit("cancelled", job_id)
return
try:
await mock_synthesize(job["text"])
await self._emit("completed", job_id)
async with self._jobs_lock:
if job_id in self._jobs:
self._jobs[job_id]["status"] = "completed"
return
except asyncio.CancelledError:
await self._emit("cancelled", job_id)
raise
except Exception as e:
async with self._jobs_lock:
if job_id in self._jobs:
self._jobs[job_id]["attempts"] = attempt
if attempt >= 3:
await self._emit("failed", job_id, error=e)
async with self._jobs_lock:
if job_id in self._jobs:
self._jobs[job_id]["status"] = "failed"
return
await asyncio.sleep(backoff)
backoff *= 2
async def submit(self, text: str, voice: str) -> str:
job_id = uuid.uuid4().hex
async with self._jobs_lock:
self._jobs[job_id] = {
"text": text, "voice": voice,
"cancelled": False, "status": "queued", "attempts": 0
}
async with self._queue_lock:
if len(self._queue) >= 100:
async with self._jobs_lock:
self._jobs.pop(job_id, None)
raise RuntimeError("Backpressure: queue full")
self._queue.append({"id": job_id, "text": text, "voice": voice})
self._queue_not_empty.notify()
await self._emit("queued", job_id)
return job_id
async def cancel(self, job_id: str) -> bool:
async with self._jobs_lock:
meta = self._jobs.get(job_id)
if not meta:
return False
if meta["status"] in ("completed", "failed", "cancelled"):
return False
meta["cancelled"] = True
removed = False
async with self._queue_lock:
for i, j in enumerate(self._queue):
if j["id"] == job_id:
del self._queue[i]
removed = True
break
if removed:
await self._emit("cancelled", job_id)
return True
async def drain(self):
while True:
async with self._queue_lock:
q_empty = len(self._queue) == 0
async with self._jobs_lock:
active_empty = len(self._active_jobs) == 0
if q_empty and active_empty:
break
await asyncio.sleep(0.01)
# ---------- tests ----------
async def main():
global _global_active, _global_max
_global_active = 0
_global_max = 0
# a) concurrency limit
pipeline = TTSPipeline()
await pipeline.start()
ids = [await pipeline.submit(f"text {i}", "v1") for i in range(50)]
await pipeline.drain()
print("max concurrency", _global_max)
assert _global_max <= 4, f"max concurrency {_global_max} > 4"
# b) backpressure
_global_active = 0; _global_max = 0
pipeline2 = TTSPipeline()
await pipeline2.start()
for i in range(100):
await pipeline2.submit(f"t{i}", "v")
try:
await pipeline2.submit("overflow", "v")
assert False, "should have raised"
except RuntimeError as e:
print("backpressure works:", e)
await pipeline2.drain()
# c) cancel mid-flight and reuse
_global_active = 0; _global_max = 0
pipeline3 = TTSPipeline()
await pipeline3.start()
events3 = []
pipeline3.register_callback(lambda e, jid, **kw: events3.append((e, jid)))
ids3 = [await pipeline3.submit(f"t{i}", "v") for i in range(20)]
await asyncio.sleep(0.05)
cancel_id = ids3[5]
await pipeline3.cancel(cancel_id)
await pipeline3.drain()
queued = [e for e in events3 if e[0] == "queued"]
completed = [e for e in events3 if e[0] == "completed"]
failed = [e for e in events3 if e[0] == "failed"]
cancelled = [e for e in events3 if e[0] == "cancelled"]
print("queued", len(queued), "finished", len(completed)+len(failed)+len(cancelled))
assert len(queued) == 20
assert len(completed) + len(failed) + len(cancelled) == 20
assert any(e[1] == cancel_id and e[0] == "cancelled" for e in events3)
# pool still usable
new_id = await pipeline3.submit("after cancel", "v")
await pipeline3.drain()
print("pool still usable")
print("All tests passed")
if __name__ == "__main__":
asyncio.run(main())
+190
View File
@@ -0,0 +1,190 @@
# webhook_bridge.py
# Python 3.11+ stdlib only
# Run: python webhook_bridge.py
import os, sys, json, hmac, hashlib, time, threading, queue, asyncio, random
import http.server, http.client
SECRET = os.getenv('WEBHOOK_SECRET', 'supersecret')
# ---------- Idempotency ----------
event_store = {}
store_lock = threading.Lock()
def evict_stale():
now = time.monotonic()
with store_lock:
stale = [k for k, v in event_store.items() if now - v > 300]
for k in stale:
del event_store[k]
# ---------- Rate limiter: token bucket 5/s ----------
CAPACITY = 5
RATE = 5.0
tokens = CAPACITY
last_refill = time.monotonic()
bucket_lock = threading.Lock()
def acquire_token():
global tokens, last_refill
while True:
with bucket_lock:
now = time.monotonic()
elapsed = now - last_refill
tokens = min(CAPACITY, tokens + elapsed * RATE)
last_refill = now
if tokens >= 1:
tokens -= 1
return
wait = (1 - tokens) / RATE
time.sleep(wait)
# ---------- Mock Discord ----------
async def discord_send(payload):
await asyncio.sleep(0.005)
if random.random() < 0.05: # ~5% 429
class Resp:
status = 429
headers = {'Retry-After': '1'}
return Resp()
class Resp:
status = 200
headers = {}
return Resp()
# ---------- Forwarding worker ----------
forward_queue = queue.Queue()
forward_log = [] # {event_id, ts}
log_lock = threading.Lock()
def worker():
while True:
item = forward_queue.get()
if item is None:
break
event_id, payload = item
try:
acquire_token()
resp = asyncio.run(discord_send(payload))
if resp.status == 429:
retry = int(resp.headers.get('Retry-After', '1'))
print(f"[WARN] 429 for {event_id}, retry after {retry}s", file=sys.stderr)
time.sleep(retry)
resp = asyncio.run(discord_send(payload))
if resp.status == 200:
with log_lock:
forward_log.append({'event_id': event_id, 'ts': time.monotonic()})
else:
print(f"[ERROR] Discord forward failed {event_id} status {resp.status}", file=sys.stderr)
except Exception as e:
print(f"[ERROR] Discord forward exception {e}", file=sys.stderr)
finally:
forward_queue.task_done()
# ---------- HTTP handler ----------
class Handler(http.server.BaseHTTPRequestHandler):
def do_POST(self):
if self.path != '/webhook':
self.send_response(404); self.end_headers(); return
length = int(self.headers.get('Content-Length', 0))
body = self.rfile.read(length)
sig = self.headers.get('X-Signature')
if not sig:
self.send_response(401); self.end_headers(); self.wfile.write(b'Missing signature'); return
expected = hmac.new(SECRET.encode(), body, hashlib.sha256).hexdigest()
if not hmac.compare_digest(expected, sig):
self.send_response(401); self.end_headers(); self.wfile.write(b'Invalid signature'); return
try:
data = json.loads(body)
except json.JSONDecodeError:
self.send_response(400); self.end_headers(); self.wfile.write(b'Invalid JSON'); return
event_id = data.get('event_id')
event_type = data.get('type')
if not event_id or not event_type:
self.send_response(400); self.end_headers(); self.wfile.write(b'Missing fields'); return
now = time.monotonic()
with store_lock:
evict_stale()
if event_id in event_store and now - event_store[event_id] < 300:
self.send_response(200); self.end_headers(); self.wfile.write(b'OK replay'); return
event_store[event_id] = now
payload = {'content': f'Event {event_type} received', 'event_id': event_id}
forward_queue.put((event_id, payload))
self.send_response(200); self.end_headers(); self.wfile.write(b'OK')
def log_message(self, fmt, *args):
print(f"{self.client_address[0]} - {fmt%args}")
# ---------- Tests ----------
def make_request(event_id, event_type, secret=SECRET, tamper=False):
body = json.dumps({'event_id': event_id, 'type': event_type, 'data': {}}).encode()
sig = hmac.new(secret.encode(), body, hashlib.sha256).hexdigest()
if tamper:
sig = '0'*64
conn = http.client.HTTPConnection('localhost', 8000, timeout=5)
conn.request('POST', '/webhook', body, {'Content-Type':'application/json','X-Signature':sig})
resp = conn.getresponse()
resp.read(); conn.close()
return resp.status
def reset_state():
with store_lock:
event_store.clear()
with log_lock:
forward_log.clear()
def run_tests():
time.sleep(0.2)
print('Test a) correct signature')
reset_state()
s = make_request('id1','chat')
time.sleep(0.1)
assert s == 200, f'expected 200 got {s}'
assert len(forward_log) == 1, 'should be forwarded once'
print(' ok')
print('Test b) tampered signature')
s = make_request('id2','chat', tamper=True)
assert s == 401, f'expected 401 got {s}'
assert len(forward_log) == 1, 'should not forward'
print(' ok')
print('Test c) replay idempotency')
s = make_request('id1','chat')
assert s == 200
time.sleep(0.05)
assert len(forward_log) == 1, 'replay must not increase count'
print(' ok')
print('Test d) rate limiter burst')
reset_state()
for i in range(10):
make_request(f'burst{i}','chat')
# wait for worker to drain
time.sleep(2.5)
assert len(forward_log) == 10, 'all 10 should eventually forward'
ts = [e['ts'] for e in forward_log]
elapsed = ts[-1] - ts[0]
assert elapsed >= 1.5, f'rate limiter not enforced, elapsed {elapsed:.2f}s'
print(f' ok, elapsed {elapsed:.2f}s >=1.5s')
print('All tests passed.')
if __name__ == '__main__':
worker_thread = threading.Thread(target=worker, daemon=True)
worker_thread.start()
server = http.server.ThreadingHTTPServer(('localhost', 8000), Handler)
srv_thread = threading.Thread(target=server.serve_forever, daemon=True)
srv_thread.start()
try:
run_tests()
finally:
server.shutdown()