Skip to content

Commit 6306dfc

Browse files
authored
Merge branch 'trunk' into deploy-ghcr
2 parents a87f7e5 + 01efc95 commit 6306dfc

17 files changed

Lines changed: 384 additions & 109 deletions

.github/workflows/docker-test.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,14 +133,14 @@ jobs:
133133
os: ubuntu-24.04-arm
134134
firefox-install-lang-package: true
135135
enable-managed-downloads: true
136-
- test-strategy: test_node_docker
136+
- test-strategy: test_node_docker_video_sidecar
137137
use-random-user: false
138138
test-video: true
139139
build-all: false
140140
os: ubuntu-24.04-arm
141141
firefox-install-lang-package: true
142142
enable-managed-downloads: false
143-
- test-strategy: test_standalone_docker
143+
- test-strategy: test_standalone_docker_video_sidecar
144144
use-random-user: false
145145
test-video: true
146146
build-all: false

Base/Dockerfile

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM ubuntu:noble@sha256:186072bba1b2f436cbb91ef2567abca677337cfc786c86e107d25b7072feef0c
1+
FROM ubuntu:noble@sha256:84e77dee7d1bc93fb029a45e3c6cb9d8aa4831ccfcc7103d36e876938d28895b
22
ARG AUTHORS=SeleniumHQ
33
LABEL authors="${AUTHORS} <docker-selenium@seleniumhq.org>"
44
LABEL org.opencontainers.image.source="https://github.com/${AUTHORS}/docker-selenium"
@@ -10,9 +10,9 @@ ARG RELEASE=selenium-${VERSION}
1010
ARG OPENTELEMETRY_VERSION=latest.release
1111
ARG GRPC_VERSION=latest.release
1212
ARG NETTY_VERSION=latest.release
13-
ARG CS_VERSION=2.1.25-M23
14-
ARG ENVSUBST_VERSION=1.5.0
15-
ARG CURL_VERSION=8.18.0
13+
ARG CS_VERSION=2.1.25-M24
14+
ARG ENVSUBST_VERSION=1.5.1
15+
ARG CURL_VERSION=8.19.0
1616
ARG PYTHON_VERSION=3.14
1717

1818
#Arguments to define the user running Selenium

Makefile

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1044,7 +1044,7 @@ test_parallel: hub chrome firefox edge chromium video
10441044
cd ./tests || true ; \
10451045
echo TAG=$(TAG_VERSION) > .env ; \
10461046
echo VIDEO_TAG=$(FFMPEG_TAG_VERSION)-$(BUILD_DATE) >> .env ; \
1047-
echo TEST_DELAY_AFTER_TEST=$(or $(TEST_DELAY_AFTER_TEST), 2) >> .env ; \
1047+
echo TEST_DELAY_AFTER_TEST=$(or $(TEST_DELAY_AFTER_TEST), 0) >> .env ; \
10481048
echo TEST_DRAIN_AFTER_SESSION_COUNT=$(or $(TEST_DRAIN_AFTER_SESSION_COUNT), 2) >> .env ; \
10491049
echo TEST_PARALLEL_HARDENING=$(or $(TEST_PARALLEL_HARDENING), "true") >> .env ; \
10501050
echo TEST_PARALLEL_COUNT=$(or $(TEST_PARALLEL_COUNT), 5) >> .env ; \
@@ -1071,10 +1071,10 @@ test_parallel: hub chrome firefox edge chromium video
10711071
make test_video_integrity
10721072

10731073
test_video_standalone: standalone_chrome standalone_chromium standalone_firefox standalone_edge
1074-
DOCKER_COMPOSE_FILE=docker-compose-v3-test-standalone.yml TEST_DELAY_AFTER_TEST=2 HUB_CHECKS_INTERVAL=45 make test_video
1074+
DOCKER_COMPOSE_FILE=docker-compose-v3-test-standalone.yml TEST_DELAY_AFTER_TEST=0 HUB_CHECKS_INTERVAL=45 make test_video
10751075

10761076
test_video_dynamic_name:
1077-
VIDEO_FILE_NAME=auto TEST_DELAY_AFTER_TEST=2 HUB_CHECKS_INTERVAL=45 TEST_ADD_CAPS_RECORD_VIDEO=false \
1077+
VIDEO_FILE_NAME=auto TEST_DELAY_AFTER_TEST=0 HUB_CHECKS_INTERVAL=45 TEST_ADD_CAPS_RECORD_VIDEO=false \
10781078
make test_video
10791079

10801080
# This should run on its own CI job. There is no need to combine it with the other tests.
@@ -1103,7 +1103,7 @@ test_video: video hub chrome firefox edge chromium
11031103
echo UID=$$(id -u) >> .env ; \
11041104
echo BINDING_VERSION=$(BINDING_VERSION) >> .env ; \
11051105
echo BASE_VERSION=$(BASE_VERSION) >> .env ; \
1106-
echo TEST_DELAY_AFTER_TEST=$(or $(TEST_DELAY_AFTER_TEST), 2) >> .env ; \
1106+
echo TEST_DELAY_AFTER_TEST=$(or $(TEST_DELAY_AFTER_TEST), 0) >> .env ; \
11071107
echo HUB_CHECKS_INTERVAL=$(or $(HUB_CHECKS_INTERVAL), 45) >> .env ; \
11081108
echo SELENIUM_ENABLE_MANAGED_DOWNLOADS=$(or $(SELENIUM_ENABLE_MANAGED_DOWNLOADS), "true") >> .env ; \
11091109
echo TEST_FIREFOX_INSTALL_LANG_PACKAGE=$${TEST_FIREFOX_INSTALL_LANG_PACKAGE} >> .env ; \
@@ -1189,9 +1189,17 @@ test_node_relay: hub node_base standalone_firefox
11891189

11901190
test_standalone_docker: standalone_docker
11911191
DOCKER_COMPOSE_FILE=docker-compose-v3-test-standalone-docker.yaml CONFIG_FILE=standalone_docker_config.toml HUB_CHECKS_INTERVAL=45 TEST_CUSTOM_SPECIFIC_NAME=true \
1192-
RECORD_STANDALONE=true GRID_URL=http://0.0.0.0:4444 LIST_OF_TESTS_AMD64="DeploymentAutoscaling" TEST_PARALLEL_HARDENING=true TEST_DELAY_AFTER_TEST=2 \
1192+
RECORD_STANDALONE=true GRID_URL=http://0.0.0.0:4444 LIST_OF_TESTS_AMD64="DeploymentAutoscaling" TEST_PARALLEL_HARDENING=true TEST_DELAY_AFTER_TEST=0 \
1193+
SELENIUM_ENABLE_MANAGED_DOWNLOADS=true LOG_LEVEL=SEVERE SKIP_CHECK_DOWNLOADS_VOLUME=true make test_node_docker
1194+
1195+
test_standalone_docker_video_sidecar: standalone_docker
1196+
DOCKER_COMPOSE_FILE=docker-compose-v3-test-standalone-docker.yaml CONFIG_FILE=standalone_docker_video_sidecar_config.toml HUB_CHECKS_INTERVAL=45 TEST_CUSTOM_SPECIFIC_NAME=true \
1197+
RECORD_STANDALONE=true GRID_URL=http://0.0.0.0:4444 LIST_OF_TESTS_AMD64="DeploymentAutoscaling" TEST_PARALLEL_HARDENING=true TEST_DELAY_AFTER_TEST=0 \
11931198
SELENIUM_ENABLE_MANAGED_DOWNLOADS=true LOG_LEVEL=SEVERE SKIP_CHECK_DOWNLOADS_VOLUME=true make test_node_docker
11941199

1200+
test_node_docker_video_sidecar:
1201+
CONFIG_FILE=config_video_sidecar.toml make test_node_docker
1202+
11951203
test_node_docker: hub standalone_docker standalone_chrome standalone_firefox standalone_edge standalone_chromium video
11961204
sudo rm -rf ./tests/tests
11971205
sudo rm -rf ./tests/videos; mkdir -p ./tests/videos/Downloads; mkdir -p ./tests/videos/upload
@@ -1214,10 +1222,10 @@ test_node_docker: hub standalone_docker standalone_chrome standalone_firefox sta
12141222
echo VIDEO_TAG=$(FFMPEG_TAG_VERSION)-$(BUILD_DATE) >> .env ; \
12151223
echo TEST_DRAIN_AFTER_SESSION_COUNT=$(or $(TEST_DRAIN_AFTER_SESSION_COUNT), 0) >> .env ; \
12161224
echo TEST_PARALLEL_HARDENING=$(or $(TEST_PARALLEL_HARDENING), "false") >> .env ; \
1217-
echo LOG_LEVEL=$(or $(LOG_LEVEL), "FINE") >> .env ; \
1225+
echo LOG_LEVEL=$(or $(LOG_LEVEL), "INFO") >> .env ; \
12181226
echo REQUEST_TIMEOUT=$(or $(REQUEST_TIMEOUT), 300) >> .env ; \
12191227
echo SELENIUM_ENABLE_MANAGED_DOWNLOADS=$(or $(SELENIUM_ENABLE_MANAGED_DOWNLOADS), "false") >> .env ; \
1220-
echo TEST_DELAY_AFTER_TEST=$(or $(TEST_DELAY_AFTER_TEST), 2) >> .env ; \
1228+
echo TEST_DELAY_AFTER_TEST=$(or $(TEST_DELAY_AFTER_TEST), 0) >> .env ; \
12211229
echo RECORD_STANDALONE=$(or $(RECORD_STANDALONE), "true") >> .env ; \
12221230
echo GRID_URL=$(or $(GRID_URL), "") >> .env ; \
12231231
echo HUB_CHECKS_INTERVAL=$(or $(HUB_CHECKS_INTERVAL), 20) >> .env ; \
@@ -1226,19 +1234,20 @@ test_node_docker: hub standalone_docker standalone_chrome standalone_firefox sta
12261234
echo UID=$$(id -u) >> .env ; \
12271235
echo BINDING_VERSION=$(BINDING_VERSION) >> .env ; \
12281236
echo BASE_VERSION=$(BASE_VERSION) >> .env ; \
1237+
echo VIDEO_EVENT_DRIVEN=$(or $(VIDEO_EVENT_DRIVEN), "true") >> .env ; \
12291238
if [ "$$(uname)" != "Darwin" ]; then \
12301239
echo HOST_IP=$$(hostname -I | awk '{print $$1}') >> .env ; \
12311240
else \
12321241
echo HOST_IP=127.0.0.1 >> .env ; \
12331242
fi; \
1243+
BASIC_AUTH_USER=admin ; \
1244+
BASIC_AUTH_PASSWORD=admin ; \
12341245
if [ "$(PLATFORMS)" = "linux/amd64" ]; then \
12351246
NODE_EDGE=edge ; \
12361247
NODE_CHROME=chrome ; \
12371248
else \
12381249
NODE_EDGE=chromium ; \
12391250
NODE_CHROME=chromium ; \
1240-
BASIC_AUTH_USER=admin ; \
1241-
BASIC_AUTH_PASSWORD=admin ; \
12421251
fi; \
12431252
echo BASIC_AUTH_USER=$${BASIC_AUTH_USER} >> .env ; \
12441253
echo BASIC_AUTH_PASSWORD=$${BASIC_AUTH_PASSWORD} >> .env ; \
@@ -1294,7 +1303,7 @@ test_video_integrity:
12941303
fi; \
12951304
for file in $$list_files; do \
12961305
echo "Checking video file: $$file"; \
1297-
docker run -u $$(id -u) -v $$(pwd):$$(pwd) -w $$(pwd) --entrypoint="" $(NAME)/video:$(FFMPEG_TAG_VERSION)-$(BUILD_DATE) ffmpeg -v error -i "$$file" -f null - ; \
1306+
docker run --rm -u $$(id -u) -v $$(pwd):$$(pwd) -w $$(pwd) --entrypoint="" $(NAME)/video:$(FFMPEG_TAG_VERSION)-$(BUILD_DATE) ffmpeg -v error -i "$$file" -f null - ; \
12981307
if [ $$? -ne 0 ]; then \
12991308
echo "Video file $$file is corrupted"; \
13001309
number_corrupted_files=$$((number_corrupted_files+1)); \
@@ -1331,7 +1340,7 @@ chart_test_autoscaling_deployment:
13311340
PLATFORMS=$(PLATFORMS) TEST_EXISTING_KEDA=true RELEASE_NAME=selenium CHART_ENABLE_TRACING=true TEST_PATCHED_KEDA=$(TEST_PATCHED_KEDA) AUTOSCALING_COOLDOWN_PERIOD=30 \
13321341
TRACING_EXPORTER_ENDPOINT=$(TRACING_EXPORTER_ENDPOINT) TEST_CUSTOM_SPECIFIC_NAME=true \
13331342
SECURE_CONNECTION_SERVER=true SECURE_USE_EXTERNAL_CERT=true SERVICE_TYPE_NODEPORT=true SELENIUM_GRID_PROTOCOL=https SELENIUM_GRID_HOST=$$(hostname -I | cut -d' ' -f1) SELENIUM_GRID_PORT=31444 \
1334-
SELENIUM_GRID_AUTOSCALING_MIN_REPLICA=1 SET_MAX_REPLICAS=3 TEST_DELAY_AFTER_TEST=2 TEST_NODE_DRAIN_AFTER_SESSION_COUNT=3 SELENIUM_GRID_MONITORING=false \
1343+
SELENIUM_GRID_AUTOSCALING_MIN_REPLICA=1 SET_MAX_REPLICAS=3 TEST_DELAY_AFTER_TEST=0 TEST_NODE_DRAIN_AFTER_SESSION_COUNT=3 SELENIUM_GRID_MONITORING=false \
13351344
VERSION=$(TAG_VERSION) VIDEO_TAG=$(FFMPEG_TAG_VERSION)-$(BUILD_DATE) KEDA_BASED_NAME=$(KEDA_BASED_NAME) KEDA_BASED_TAG=$(KEDA_BASED_TAG) NAMESPACE=$(NAMESPACE) BINDING_VERSION=$(BINDING_VERSION) BASE_VERSION=$(BASE_VERSION) \
13361345
TEMPLATE_OUTPUT_FILENAME="k8s_prefixSelenium_enableTracing_secureServer_externalCerts_nodePort_autoScaling_scaledObject_existingKEDA_subPath.yaml" \
13371346
./tests/charts/make/chart_test.sh DeploymentAutoscaling

StandaloneDocker/Dockerfile

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,6 @@ ENV SE_SESSION_REQUEST_TIMEOUT="300" \
2121
# Boolean value, maps "--relax-checks"
2222
SE_RELAX_CHECKS="true" \
2323
SE_OTEL_SERVICE_NAME="selenium-standalone-docker" \
24-
SE_NODE_ENABLE_MANAGED_DOWNLOADS="true"
24+
SE_NODE_ENABLE_MANAGED_DOWNLOADS="true" \
25+
SE_BIND_BUS="true" \
26+
SE_EVENT_BUS_IMPLEMENTATION=""

StandaloneDocker/start-selenium-grid-docker.sh

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,19 @@ if [ ! -z "${SE_EVENT_BUS_HEARTBEAT_PERIOD}" ]; then
108108
append_se_opts "--eventbus-heartbeat-period" "${SE_EVENT_BUS_HEARTBEAT_PERIOD}"
109109
fi
110110

111+
if [ ! -z "${SE_EVENT_BUS_IMPLEMENTATION}" ]; then
112+
append_se_opts "--events-implementation" "${SE_EVENT_BUS_IMPLEMENTATION}"
113+
fi
114+
115+
if [ "${SE_BIND_BUS}" = "true" ]; then
116+
append_se_opts "--bind-bus" "${SE_BIND_BUS}"
117+
append_se_opts "--publish-events" "tcp://*:${SE_EVENT_BUS_PUBLISH_PORT}"
118+
append_se_opts "--subscribe-events" "tcp://*:${SE_EVENT_BUS_SUBSCRIBE_PORT}"
119+
if [ -z "${SE_EVENT_BUS_IMPLEMENTATION}" ]; then
120+
append_se_opts "--events-implementation" "org.openqa.selenium.events.zeromq.ZeroMqEventBus"
121+
fi
122+
fi
123+
111124
if [ "${SE_ENABLE_TLS}" = "true" ]; then
112125
# Configure truststore for the server
113126
if [ ! -z "$SE_JAVA_SSL_TRUST_STORE" ]; then

Video/recorder.conf

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ killasgroup=true
2020
autostart=%(ENV_SE_RECORD_VIDEO)s
2121
startsecs=0
2222
autorestart=%(ENV_SE_RECORD_VIDEO)s
23-
stopsignal=KILL
23+
stopsignal=TERM
24+
stopwaitsecs=5
2425

2526
;Logs (all activity redirected to stdout so it can be seen through "docker logs"
2627
redirect_stderr=true

Video/video.sh

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -212,9 +212,15 @@ function graceful_exit() {
212212
wait_util_uploader_shutdown
213213
}
214214

215+
_graceful_exit_done=false
215216
function graceful_exit_force() {
217+
if [[ "$_graceful_exit_done" = "true" ]]; then
218+
return
219+
fi
220+
_graceful_exit_done=true
216221
graceful_exit
217-
kill -SIGTERM "$(cat ${SE_SUPERVISORD_PID_FILE})" 2>/dev/null
222+
# Supervisord signaling is delegated to the Python controller (video_recorder.py)
223+
# which handles it uniformly for both shell and event-driven modes.
218224
echo "$(date -u +"${ts_format}") [${process_name}] - Ready to shutdown the recorder"
219225
exit 0
220226
}
@@ -234,7 +240,7 @@ if [[ "${VIDEO_UPLOAD_ENABLED}" != "true" ]] && [[ "${VIDEO_FILE_NAME}" != "auto
234240
-probesize 32M -analyzeduration 0 -y -f x11grab -video_size ${VIDEO_SIZE} -r ${FRAME_RATE} \
235241
-i ${DISPLAY} ${SE_AUDIO_SOURCE} -codec:v ${CODEC} ${PRESET:-"-preset veryfast"} \
236242
-tune zerolatency -crf ${SE_VIDEO_CRF:-28} -maxrate ${SE_VIDEO_MAXRATE:-1000k} -bufsize ${SE_VIDEO_BUFSIZE:-2000k} \
237-
-pix_fmt yuv420p -movflags +faststart "$video_file" &
243+
-pix_fmt yuv420p -movflags frag_keyframe+empty_moov+default_base_moof "$video_file" &
238244
FFMPEG_PID=$!
239245
if ps -p $FFMPEG_PID >/dev/null; then
240246
wait $FFMPEG_PID
@@ -270,7 +276,7 @@ else
270276
-probesize 32M -analyzeduration 0 -y -f x11grab -video_size ${VIDEO_SIZE} -r ${FRAME_RATE} \
271277
-i ${DISPLAY} ${SE_AUDIO_SOURCE} -codec:v ${CODEC} ${PRESET:-"-preset veryfast"} \
272278
-tune zerolatency -crf ${SE_VIDEO_CRF:-28} -maxrate ${SE_VIDEO_MAXRATE:-1000k} -bufsize ${SE_VIDEO_BUFSIZE:-2000k} \
273-
-pix_fmt yuv420p -movflags +faststart "$video_file" &
279+
-pix_fmt yuv420p -movflags frag_keyframe+empty_moov+default_base_moof "$video_file" &
274280
FFMPEG_PID=$!
275281
if ps -p $FFMPEG_PID >/dev/null; then
276282
recording_started="true"

Video/video_ready.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,10 @@ def do_GET(self):
2828

2929
def graceful_shutdown(signum, frame):
3030
print("Trapped SIGTERM/SIGINT/x so shutting down video-ready...")
31-
httpd.shutdown()
31+
# httpd.shutdown() must be called from a different thread than serve_forever()
32+
# or it deadlocks. video-ready has no state to drain, so close the socket
33+
# and exit directly — supervisord will see the clean exit immediately.
34+
httpd.server_close()
3235
sys.exit(0)
3336

3437

Video/video_recorder.py

Lines changed: 83 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,61 @@
66
77
When event-driven mode is enabled, this launches a single unified service
88
that handles both recording and uploading with shared state management.
9+
10+
After the video service exits for any reason (normal drain, session end, or
11+
supervisord-initiated shutdown), this controller signals supervisord so the
12+
container shuts down. Centralising this here means both shell and event-driven
13+
modes have identical container-lifecycle behaviour without video.sh needing to
14+
know about supervisord.
915
"""
1016

1117
import os
18+
import signal
1219
import subprocess
1320
import sys
1421

1522

23+
def _signal_supervisord() -> None:
24+
"""Signal supervisord to initiate a container-wide shutdown.
25+
26+
Safe to call even when supervisord is already shutting down — it will
27+
simply ignore a repeated SIGTERM if it is already in SHUTDOWN state.
28+
"""
29+
pid_file = os.environ.get("SE_SUPERVISORD_PID_FILE", "")
30+
if not pid_file:
31+
return
32+
try:
33+
with open(pid_file) as f:
34+
pid = int(f.read().strip())
35+
os.kill(pid, signal.SIGTERM)
36+
print("[video.recorder] - Signaled supervisord to shut down")
37+
except (OSError, ValueError, FileNotFoundError):
38+
pass
39+
40+
1641
def main():
1742
event_driven = os.environ.get("SE_VIDEO_EVENT_DRIVEN", "false").lower() == "true"
1843

1944
if event_driven:
2045
print("Starting unified event-driven video service...")
2146
print("This service handles both recording and uploading with shared state.")
47+
48+
# Capture whether shutdown was externally initiated (SIGTERM/SIGINT)
49+
# before asyncio.run() replaces the signal handlers via add_signal_handler.
50+
_external_shutdown = [False]
51+
52+
def _mark_external_shutdown(signum, frame):
53+
_external_shutdown[0] = True
54+
# This handler is only reachable before asyncio.run() installs its
55+
# own handlers via loop.add_signal_handler(). Setting the flag and
56+
# returning would swallow the signal — nothing would act on it and
57+
# the process would hang inside asyncio.run() indefinitely.
58+
# Exit immediately so supervisord sees a clean stop.
59+
sys.exit(0)
60+
61+
signal.signal(signal.SIGTERM, _mark_external_shutdown)
62+
signal.signal(signal.SIGINT, _mark_external_shutdown)
63+
2264
try:
2365
import asyncio
2466

@@ -29,10 +71,49 @@ def main():
2971
print(f"Failed to import video service: {e}")
3072
print("Ensure pyzmq is installed: pip install pyzmq")
3173
print("Falling back to shell-based recording...")
32-
subprocess.run(["/opt/bin/video.sh"], check=True)
74+
_run_shell_recorder()
75+
return
76+
77+
# Only trigger container shutdown for self-initiated exits (drain).
78+
if not _external_shutdown[0]:
79+
_signal_supervisord()
3380
else:
3481
print("Starting shell-based video recording...")
35-
subprocess.run(["/opt/bin/video.sh"], check=True)
82+
_run_shell_recorder()
83+
84+
85+
def _run_shell_recorder():
86+
proc = subprocess.Popen(["/opt/bin/video.sh"])
87+
_external_shutdown = False # True when supervisord (or user) told us to stop
88+
89+
def forward_signal(signum, frame):
90+
nonlocal _external_shutdown
91+
# Forward the signal to video.sh at most once. supervisord uses
92+
# killasgroup=true so video.sh already received the signal directly;
93+
# re-forwarding on every re-entrant call amplifies the SIGTERM
94+
# ping-pong and can keep the process alive for 60 s.
95+
if not _external_shutdown:
96+
_external_shutdown = True
97+
try:
98+
proc.send_signal(signum)
99+
except ProcessLookupError:
100+
pass # Process already exited before signal was forwarded
101+
proc.wait()
102+
103+
signal.signal(signal.SIGTERM, forward_signal)
104+
signal.signal(signal.SIGINT, forward_signal)
105+
rc = proc.wait()
106+
107+
# Signal supervisord only for self-initiated exits (drain, node gone).
108+
# If the shutdown came FROM supervisord (_external_shutdown=True) it is
109+
# already in SHUTDOWN state — signalling it again is a no-op at best and
110+
# confusing at worst. If the recorder crashed (rc != 0) we must not bring
111+
# down the Selenium process alongside it.
112+
if not _external_shutdown and rc == 0:
113+
_signal_supervisord()
114+
115+
if rc != 0:
116+
sys.exit(rc)
36117

37118

38119
if __name__ == "__main__":

0 commit comments

Comments
 (0)