File

FILE: projects/low_latency_relay_v2.py
SIZE: 5123 bytes
SHA256: 7e65993f482ef7b6c5cae323800ab445bc8cfba59196a2fc6ad2d10ffa32793f
Lines: 158

Use path as FILE | Patch Context | Read first 100 | Read prev 100 | Read next 100 | Git diff this file | Code Buffers | Active Patch Context

Blocks / Symbols (python)

LineTextActions
1
from pathlib import Path
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
2
from collections import deque
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
3
import json
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
4
import queue
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
5
import sys
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
6
import threading
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
7
import time
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
8
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
9
ROOT = Path(__file__).resolve().parents[1]
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
10
sys.path.insert(0, str(ROOT))
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
11
import sheet_relay as sr
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
12
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
13
LIVE_REVISION = "20260830-107-LL2"
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
14
sr.REVISION = LIVE_REVISION
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
15
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
16
POLL_WORKERS = 3
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
17
POLL_STAGGER_SECONDS = 0.70
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
18
POLL_ERROR_BACKOFF_SECONDS = 0.75
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
19
HEARTBEAT_INTERVAL_SECONDS = 60.0
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
20
MONITOR_INTERVAL_SECONDS = 60.0
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
21
EXECUTOR_IDLE_SECONDS = 0.25
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
22
MAX_SEEN_COMMANDS = 4096
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
23
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
24
command_queue = queue.Queue()
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
25
stop_event = threading.Event()
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
26
seen_lock = threading.Lock()
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
27
seen_ids = set()
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
28
seen_order = deque()
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
29
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
30
def enqueue_once(command):
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
31
    command_id = str(command.get("id") or "")
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
32
    if not command_id:
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
33
        sr.log("LL2 dropped command without id")
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
34
        return False
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
35
    with seen_lock:
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
36
        if command_id in seen_ids:
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
37
            sr.log(f"LL2 duplicate claim suppressed id={command_id}")
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
38
            return False
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
39
        seen_ids.add(command_id)
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
40
        seen_order.append(command_id)
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
41
        while len(seen_order) > MAX_SEEN_COMMANDS:
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
42
            seen_ids.discard(seen_order.popleft())
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
43
    command_queue.put(command)
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
44
    return True
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
45
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
46
def process_command(cfg, command):
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
47
    sr.log(f"claimed command id={command.get('id')} action={command.get('action')}")
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
48
    task_id = ""
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
49
    try:
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
50
        task_id = str(json.loads(command.get("payload_json") or "{}").get("task_id", ""))
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
51
    except (TypeError, ValueError):
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
52
        pass
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
53
    sr.record_task_event(
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
54
        task_id,
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
55
        "command_started",
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
56
        command_id=command.get("id"),
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
57
        action=command.get("action"),
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
58
    )
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
59
    try:
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
60
        command_result = sr.execute_command(cfg, command)
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
61
        sr.record_task_event(
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
62
            task_id,
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
63
            "command_completed" if command_result.get("status") == "done" else "command_failed",
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
64
            command_id=command.get("id"),
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
65
            action=command.get("action"),
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
66
            relay_status=command_result.get("status"),
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
67
            http_status=command_result.get("http_status"),
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
68
        )
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
69
        sr.send_result(cfg, command_result)
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
70
    except Exception as exc:
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
71
        sr.record_task_event(
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
72
            task_id,
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
73
            "command_failed",
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
74
            command_id=command.get("id"),
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
75
            action=command.get("action"),
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
76
            error=type(exc).__name__,
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
77
        )
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
78
        sr.send_result(
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
79
            cfg,
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
80
            sr.result(command.get("id", ""), "error", "", "", str(exc), time.time()),
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
81
        )
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
82
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
83
def poll_worker(cfg, worker_index):
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
84
    if worker_index:
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
85
        time.sleep(POLL_STAGGER_SECONDS * worker_index)
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
86
    sr.log(f"LL2 poll worker {worker_index} online")
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
87
    while not stop_event.is_set():
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
88
        try:
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
89
            status, data = sr.http_json(sr.web_app_url(cfg, "poll"), timeout=45)
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
90
            if status != 200:
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
91
                sr.log(f"LL2 poll worker {worker_index} http={status}")
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
92
                time.sleep(POLL_ERROR_BACKOFF_SECONDS)
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
93
                continue
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
94
            command = data.get("command")
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
95
            if command:
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
96
                enqueue_once(command)
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
97
        except Exception as exc:
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
98
            sr.log(f"LL2 poll worker {worker_index} error: {type(exc).__name__}: {exc}")
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
99
            time.sleep(POLL_ERROR_BACKOFF_SECONDS)
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
100
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
101
def maintenance_worker(cfg):
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
102
    next_heartbeat = 0.0
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
103
    next_monitor = 0.0
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
104
    sr.log("LL2 maintenance worker online")
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
105
    while not stop_event.is_set():
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
106
        now = time.monotonic()
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
107
        if now >= next_heartbeat:
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
108
            try:
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
109
                sr.heartbeat(cfg, sr.bridge_health(cfg))
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
110
            except Exception as exc:
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
111
                sr.log(f"LL2 heartbeat error: {type(exc).__name__}: {exc}")
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
112
            next_heartbeat = time.monotonic() + HEARTBEAT_INTERVAL_SECONDS
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
113
        if time.monotonic() >= next_monitor:
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
114
            try:
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
115
                sr.monitor_verifies(cfg)
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
116
            except Exception as exc:
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
117
                sr.log(f"LL2 monitor error: {type(exc).__name__}: {exc}")
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
118
            next_monitor = time.monotonic() + MONITOR_INTERVAL_SECONDS
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
119
        stop_event.wait(0.25)
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
120
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
121
def run_loop():
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
122
    cfg = sr.require_config()
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
123
    sr.log(
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
124
        f"low-latency relay starting revision={LIVE_REVISION} "
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
125
        f"poll_workers={POLL_WORKERS} stagger={POLL_STAGGER_SECONDS:.2f}s "
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
126
        "maintenance=background execution=serial dedup=command-id"
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
127
    )
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
128
    threading.Thread(
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
129
        target=maintenance_worker,
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
130
        args=(cfg,),
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
131
        name="sheet-maintenance",
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
132
        daemon=True,
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
133
    ).start()
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
134
    for worker_index in range(POLL_WORKERS):
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
135
        threading.Thread(
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
136
            target=poll_worker,
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
137
            args=(cfg, worker_index),
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
138
            name=f"sheet-poll-{worker_index}",
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
139
            daemon=True,
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
140
        ).start()
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
141
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
142
    try:
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
143
        while True:
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
144
            try:
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
145
                command = command_queue.get(timeout=EXECUTOR_IDLE_SECONDS)
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
146
            except queue.Empty:
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
147
                continue
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
148
            try:
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
149
                process_command(cfg, command)
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
150
            finally:
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
151
                command_queue.task_done()
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
152
    except KeyboardInterrupt:
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
153
        sr.log("low-latency relay LL2 stopped by keyboard interrupt")
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
154
    finally:
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
155
        stop_event.set()
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
156
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
157
if __name__ == "__main__":
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A
158
    run_loop()
Use FILE Use as OLD Use as NEW Open Patch Composer +/-3 CONTEXT +/-10 CONTEXT +/-25 CONTEXT Append to Buffer A