mirror of
https://github.com/hansjone/netx.git
synced 2026-10-09 03:10:46 +08:00
fix(ume): cancel alarm subscription with DELETE and surface failures
Use DELETE delete-subscription, refresh token before cancel, recover orphan subs on establish, and keep local state when UME delete fails. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
4f8735a83f
commit
a8b359f60d
4 changed files with 110 additions and 19 deletions
|
|
@ -2,6 +2,7 @@ from __future__ import annotations
|
|||
|
||||
import json
|
||||
import logging
|
||||
import re
|
||||
import ssl
|
||||
import threading
|
||||
import time
|
||||
|
|
@ -22,6 +23,14 @@ from .ume_sync_service import apply_alarm_to_current, extract_alarm_from_notific
|
|||
|
||||
_ws_log = logging.getLogger("netx.ume.alarm_ws")
|
||||
|
||||
_ORPHAN_SUB_ID_RE = re.compile(r"id:([0-9a-fA-F-]{8}-[0-9a-fA-F-]{4}-[0-9a-fA-F-]{4}-[0-9a-fA-F-]{4}-[0-9a-fA-F-]{12})")
|
||||
|
||||
|
||||
def parse_subscription_id_from_already_exists_error(message: str) -> str:
|
||||
"""Extract subscription id from UME 400 'topic subscription already exist, id:...'."""
|
||||
m = _ORPHAN_SUB_ID_RE.search(str(message or ""))
|
||||
return m.group(1).strip() if m else ""
|
||||
|
||||
_shutdown_lock = threading.Lock()
|
||||
_subscription_lock = threading.Lock()
|
||||
_ws_wake_event = threading.Event()
|
||||
|
|
@ -146,7 +155,15 @@ def establish_alarm_subscription_manual(client: UMEClient, db: Session) -> dict[
|
|||
raise RuntimeError("ume_ws_no_valid_token")
|
||||
|
||||
topic = str(getattr(settings, "ume_notification_topic", "ALARM") or "ALARM").strip() or "ALARM"
|
||||
sub_id, uri = client.establish_alarm_subscription(topic=topic)
|
||||
try:
|
||||
sub_id, uri = client.establish_alarm_subscription(topic=topic)
|
||||
except RuntimeError as exc:
|
||||
orphan_id = parse_subscription_id_from_already_exists_error(str(exc))
|
||||
if not orphan_id:
|
||||
raise
|
||||
_ws_log.warning("establish: UME reports existing subscription id=%s, deleting then retry", orphan_id)
|
||||
_delete_subscription_on_ume(client, orphan_id)
|
||||
sub_id, uri = client.establish_alarm_subscription(topic=topic)
|
||||
save_subscription(db, subscription_id=sub_id, wss_uri=uri, topic=topic)
|
||||
db.commit()
|
||||
|
||||
|
|
@ -166,12 +183,8 @@ def cancel_alarm_subscription_manual(client: UMEClient, db: Session) -> dict[str
|
|||
if not sub_id and loaded is not None:
|
||||
sub_id = str(loaded[0] or "")
|
||||
if sub_id:
|
||||
try:
|
||||
client._sync_token_from_store()
|
||||
if client.has_valid_token():
|
||||
_delete_subscription_on_ume(client, sub_id)
|
||||
except Exception as exc:
|
||||
_ws_log.warning("cancel subscription on UME failed: %s", exc)
|
||||
client.refresh_if_needed()
|
||||
_delete_subscription_on_ume(client, sub_id)
|
||||
|
||||
clear_subscription(db, cache_key=DEFAULT_SUBSCRIPTION_KEY)
|
||||
db.commit()
|
||||
|
|
|
|||
|
|
@ -622,17 +622,12 @@ class UMEClient:
|
|||
return sub_id, uri
|
||||
|
||||
def delete_alarm_subscription(self, subscription_id: str) -> None:
|
||||
"""DELETE delete-subscription with body {\"input\": {\"id\": ...}} (same headers as alarm REST)."""
|
||||
sub_id = str(subscription_id or "").strip()
|
||||
if not sub_id:
|
||||
return
|
||||
self._sync_token_from_store()
|
||||
if not self.has_valid_token():
|
||||
return
|
||||
body = {"input": {"id": sub_id}}
|
||||
try:
|
||||
self._request_json_with_current_token("POST", self.notification_delete_path, body=body)
|
||||
except Exception:
|
||||
return
|
||||
self.request_json("DELETE", self.notification_delete_path, body=body)
|
||||
|
||||
def has_valid_token(self) -> bool:
|
||||
"""True when a non-expired token is present in memory (call _sync_token_from_store first)."""
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue