-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Expand file tree
/
Copy pathvideo_recorder.py
More file actions
executable file
·114 lines (90 loc) · 4.03 KB
/
video_recorder.py
File metadata and controls
executable file
·114 lines (90 loc) · 4.03 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#!/usr/bin/env python3
"""
Video service entry point that switches between:
1. Unified event-driven service (SE_VIDEO_EVENT_DRIVEN=true)
2. Traditional shell-based polling (SE_VIDEO_EVENT_DRIVEN=false or unset)
When event-driven mode is enabled, this launches a single unified service
that handles both recording and uploading with shared state management.
After the video service exits for any reason (normal drain, session end, or
supervisord-initiated shutdown), this controller signals supervisord so the
container shuts down. Centralising this here means both shell and event-driven
modes have identical container-lifecycle behaviour without video.sh needing to
know about supervisord.
"""
import os
import signal
import subprocess
import sys
def _signal_supervisord() -> None:
"""Signal supervisord to initiate a container-wide shutdown.
Safe to call even when supervisord is already shutting down — it will
simply ignore a repeated SIGTERM if it is already in SHUTDOWN state.
"""
pid_file = os.environ.get("SE_SUPERVISORD_PID_FILE", "")
if not pid_file:
return
try:
with open(pid_file) as f:
pid = int(f.read().strip())
os.kill(pid, signal.SIGTERM)
print("[video.recorder] - Signaled supervisord to shut down")
except (OSError, ValueError, FileNotFoundError):
pass
def main():
event_driven = os.environ.get("SE_VIDEO_EVENT_DRIVEN", "false").lower() == "true"
if event_driven:
print("Starting unified event-driven video service...")
print("This service handles both recording and uploading with shared state.")
# Capture whether shutdown was externally initiated (SIGTERM/SIGINT)
# before asyncio.run() replaces the signal handlers via add_signal_handler.
_external_shutdown = [False]
def _mark_external_shutdown(signum, frame):
_external_shutdown[0] = True
signal.signal(signal.SIGTERM, _mark_external_shutdown)
signal.signal(signal.SIGINT, _mark_external_shutdown)
try:
import asyncio
from video_service import main as service_main
asyncio.run(service_main())
except ImportError as e:
print(f"Failed to import video service: {e}")
print("Ensure pyzmq is installed: pip install pyzmq")
print("Falling back to shell-based recording...")
_run_shell_recorder()
return
# Only trigger container shutdown for self-initiated exits (drain).
if not _external_shutdown[0]:
_signal_supervisord()
else:
print("Starting shell-based video recording...")
_run_shell_recorder()
def _run_shell_recorder():
proc = subprocess.Popen(["/opt/bin/video.sh"])
_external_shutdown = False # True when supervisord (or user) told us to stop
def forward_signal(signum, frame):
nonlocal _external_shutdown
# Forward the signal to video.sh at most once. supervisord uses
# killasgroup=true so video.sh already received the signal directly;
# re-forwarding on every re-entrant call amplifies the SIGTERM
# ping-pong and can keep the process alive for 60 s.
if not _external_shutdown:
_external_shutdown = True
try:
proc.send_signal(signum)
except ProcessLookupError:
pass # Process already exited before signal was forwarded
proc.wait()
signal.signal(signal.SIGTERM, forward_signal)
signal.signal(signal.SIGINT, forward_signal)
rc = proc.wait()
# Signal supervisord only for self-initiated exits (drain, node gone).
# If the shutdown came FROM supervisord (_external_shutdown=True) it is
# already in SHUTDOWN state — signalling it again is a no-op at best and
# confusing at worst. If the recorder crashed (rc != 0) we must not bring
# down the Selenium process alongside it.
if not _external_shutdown and rc == 0:
_signal_supervisord()
if rc != 0:
sys.exit(rc)
if __name__ == "__main__":
main()