4b6817381b
CI (OpenClaw E2E) / openclaw test (push) Has been cancelled
CI / coverage-report (push) Has been cancelled
CI / test-kubernetes (push) Has been cancelled
CI / should-run-thorough (push) Has been cancelled
CI / test-thorough (cloudwatch-demo) (push) Has been cancelled
CI / test-thorough (flink-ecs) (push) Has been cancelled
CI / test-thorough (upstream-lambda) (push) Has been cancelled
CI / test-thorough (prefect-ecs-fargate) (push) Has been cancelled
Release / build-binaries (zip, opensre.exe, onefile, windows-latest, windows-x64) (push) Has been cancelled
Benchmark image — build + push to ECR (any adapter) / build + push (push) Has been cancelled
CI / quality (ubuntu-latest) (push) Has been cancelled
CI / test (tools-runtime) (push) Has been cancelled
CI / test (e2e-general) (push) Has been cancelled
CI / test (cli-runtime) (push) Has been cancelled
CI / test (e2e-provider-and-openclaw) (push) Has been cancelled
CI / test (integrations-and-misc) (push) Has been cancelled
Release / verify (push) Has been cancelled
Release / build-python-dist (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, macos-15-intel, darwin-x64) (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, macos-latest, darwin-arm64) (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, ubuntu-22.04, linux-x64) (push) Has been cancelled
Release / publish-release (push) Has been cancelled
Release / publish-main-release (push) Has been cancelled
Interactive Shell Live (PR + post-merge) / turn-checks (no-LLM) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Interactive Shell Live (PR + post-merge) / turn-live shard ${{ matrix.shard_index }} (push) Has been cancelled
Release / prepare (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, ubuntu-22.04-arm, linux-arm64) (push) Has been cancelled
Synthetic Deterministic Tests / Synthetic offline (deterministic) (push) Has been cancelled
103 lines
2.7 KiB
Python
103 lines
2.7 KiB
Python
"""In-process alert inbox — the pure domain queue for external alert pushes.
|
|
|
|
HTTP intake lives in :mod:`gateway.webapp` (``POST /alerts``); this module only
|
|
owns the queue and the process-wide current-inbox handle.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import threading
|
|
from collections import deque
|
|
from datetime import datetime
|
|
|
|
from config.strict_config import StrictConfigModel
|
|
|
|
_DEFAULT_MAX_INBOX = 256
|
|
|
|
|
|
class IncomingAlert(StrictConfigModel):
|
|
text: str
|
|
alert_name: str | None = None
|
|
severity: str | None = None
|
|
source: str | None = None
|
|
received_at: datetime | None = None
|
|
|
|
|
|
class AlertInbox:
|
|
def __init__(self, maxsize: int = _DEFAULT_MAX_INBOX) -> None:
|
|
self._queue: deque[IncomingAlert] = deque()
|
|
self._maxsize = maxsize
|
|
self._dropped: int = 0
|
|
self._lock = threading.Lock()
|
|
self._pending_event = threading.Event() # Set when alerts are available
|
|
|
|
def put(self, alert: IncomingAlert) -> bool:
|
|
"""Return True if queued without eviction, False if an old alert was dropped."""
|
|
with self._lock:
|
|
if len(self._queue) >= self._maxsize:
|
|
self._queue.popleft()
|
|
self._dropped += 1
|
|
self._queue.append(alert)
|
|
self._pending_event.set()
|
|
return False
|
|
self._queue.append(alert)
|
|
self._pending_event.set()
|
|
return True
|
|
|
|
def pop_nowait(self) -> IncomingAlert | None:
|
|
with self._lock:
|
|
try:
|
|
return self._queue.popleft()
|
|
except IndexError:
|
|
return None
|
|
|
|
def iter_pending(self) -> list[IncomingAlert]:
|
|
with self._lock:
|
|
items: list[IncomingAlert] = []
|
|
while True:
|
|
try:
|
|
items.append(self._queue.popleft())
|
|
except IndexError:
|
|
break
|
|
if not self._queue:
|
|
self._pending_event.clear()
|
|
return items
|
|
|
|
def peek_last(self, n: int) -> list[IncomingAlert]:
|
|
with self._lock:
|
|
items = list(self._queue)
|
|
return items[-n:]
|
|
|
|
@property
|
|
def qsize(self) -> int:
|
|
return len(self._queue)
|
|
|
|
@property
|
|
def dropped(self) -> int:
|
|
return self._dropped
|
|
|
|
@property
|
|
def pending_event(self) -> threading.Event:
|
|
"""Event set when alerts are available, for background wakers."""
|
|
return self._pending_event
|
|
|
|
|
|
_current_inbox: AlertInbox | None = None
|
|
|
|
|
|
def set_current_inbox(inbox: AlertInbox | None) -> None:
|
|
global _current_inbox
|
|
_current_inbox = inbox
|
|
|
|
|
|
def get_current_inbox() -> AlertInbox | None:
|
|
return _current_inbox
|
|
|
|
|
|
__all__ = [
|
|
"AlertInbox",
|
|
"IncomingAlert",
|
|
"get_current_inbox",
|
|
"set_current_inbox",
|
|
]
|