Skip to content

Docker: Video recording starts via session capability se:recordVideo#3131

Open
VietND96 wants to merge 1 commit intotrunkfrom
video-shutdown
Open

Docker: Video recording starts via session capability se:recordVideo#3131
VietND96 wants to merge 1 commit intotrunkfrom
video-shutdown

Conversation

@VietND96
Copy link
Copy Markdown
Member

@VietND96 VietND96 commented May 9, 2026

Thanks for contributing to the Docker-Selenium project!
A PR well described will help maintainers to quickly review and merge it

Before submitting your PR, please check our contributing guidelines, applied for this repository.
Avoid large PRs, help reviewers by making them as simple and short as possible.

Description

Motivation and Context

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist

  • I have read the contributing document.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have added tests to cover my changes.
  • All new and existing tests passed.

Signed-off-by: Viet Nguyen Duc <nguyenducviet4496@gmail.com>
@qodo-code-review
Copy link
Copy Markdown
Contributor

Review Summary by Qodo

Enable video recording control via SE_RECORD_VIDEO environment variable

✨ Enhancement

Grey Divider

Walkthroughs

Description
• Add SE_RECORD_VIDEO environment variable support for default video recording behavior
• Implement fallback logic when session capability is absent or undefined
• Refactor supervisord configuration to always start video services with runtime control
• Improve signal handling in shell-based video recorder to prevent blocking
• Add idle mode when video recording is disabled and per-session mode is inactive
Diagram
flowchart LR
  A["Session Capability<br/>se:recordVideo"] -->|Present| B["Use Capability Value"]
  C["SE_RECORD_VIDEO<br/>Environment Variable"] -->|Absent Capability| B
  B --> D["Determine Recording<br/>Status"]
  D -->|Enabled| E["Start Video Recording"]
  D -->|Disabled| F["Idle Mode"]
  G["Supervisord Config"] -->|Always Start| H["Video Services"]
  H --> I["Runtime Control<br/>via Python Logic"]
Loading

Grey Divider

File Changes

1. Video/video_nodeQuery.py ✨ Enhancement +5/-2

Add SE_RECORD_VIDEO fallback for video recording control

• Add SE_RECORD_VIDEO environment variable with default value "true"
• Implement fallback logic to use environment variable when session capability is absent
• Normalize record_video value to "true" or "false" string based on capability or environment
 variable

Video/video_nodeQuery.py


2. Video/video_recorder.py ✨ Enhancement +17/-6

Implement idle mode and fix signal handler blocking

• Import time module for idle loop functionality
• Add early return with idle sleep loop when video recording is disabled and per-session mode is
 inactive
• Improve signal handler to avoid blocking on proc.wait() inside signal handler
• Remove redundant comment about signal forwarding behavior

Video/video_recorder.py


3. NodeBase/Dockerfile ⚙️ Configuration changes +2/-2

Quote environment variable values in Dockerfile

• Quote SE_RECORD_VIDEO and SE_VIDEO_FILE_NAME environment variable values for consistency

NodeBase/Dockerfile


View more (2)
4. Video/recorder.conf ⚙️ Configuration changes +4/-4

Always start video-recording service with runtime control

• Change autostart and autorestart from environment variable interpolation to hardcoded true
• Move video recording control logic from supervisord configuration to Python runtime

Video/recorder.conf


5. Video/uploader.conf ⚙️ Configuration changes +2/-2

Always start video-upload service with runtime control

• Change autostart and autorestart from environment variable interpolation to hardcoded true
• Move upload service control logic from supervisord configuration to Python runtime

Video/uploader.conf


Grey Divider

Qodo Logo

@qodo-code-review
Copy link
Copy Markdown
Contributor

qodo-code-review Bot commented May 9, 2026

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (1)

Grey Divider


Action required

1. KeyboardInterrupt swallowed in idle 📘 Rule violation ☼ Reliability
Description
In the new idle path, KeyboardInterrupt is caught and ignored, causing SIGINT to exit cleanly
instead of preserving default interrupt termination semantics. This violates the requirement that
pre-async SIGINT handling must not be swallowed, and can misclassify external shutdown as a normal
exit.
Code

Video/video_recorder.py[R92-97]

+        try:
+            while True:
+                time.sleep(60)
+        except KeyboardInterrupt:
+            pass
+        return
Evidence
PR Compliance ID 1 requires that pre-async signal handling must preserve termination semantics (not
swallowing SIGINT). The added idle loop catches KeyboardInterrupt and then returns, effectively
converting SIGINT into a successful/normal exit.

Video/video_recorder.py[92-97]
Best Practice: Learned patterns

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`Video/video_recorder.py` introduces an idle loop that catches `KeyboardInterrupt` and ignores it, which changes SIGINT behavior from default interrupt termination to a clean/normal exit.

## Issue Context
Compliance requires that pre-async SIGINT termination semantics are preserved (i.e., SIGINT should not be swallowed/misclassified as a normal exit).

## Fix Focus Areas
- Video/video_recorder.py[92-97]

## Suggested direction
- Remove the `try/except KeyboardInterrupt` block entirely, or
- Re-raise `KeyboardInterrupt` after any necessary logging/cleanup, or
- Explicitly exit with an interrupt-like code (e.g., `raise` or `sys.exit(130)`) so termination semantics are preserved.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. FILE_NAME bypasses recorder gating 🐞 Bug ≡ Correctness
Description
In shell mode, video_recorder._run_shell_recorder() decides whether to idle using only
SE_VIDEO_FILE_NAME, but video.sh uses FILE_NAME to override the effective filename/mode. This
mismatch can make recording start in fixed-file mode even with SE_RECORD_VIDEO=false (bypassing
capability-based gating) or make the recorder idle when video.sh would run per-session mode.
Code

Video/video_recorder.py[R87-92]

+    record_video = os.environ.get("SE_RECORD_VIDEO", "true").lower() == "true"
+    per_session_mode = os.environ.get("SE_VIDEO_FILE_NAME", "") == "auto"
+
+    if not record_video and not per_session_mode:
+        print("[video.recorder] - SE_RECORD_VIDEO is disabled and SE_VIDEO_FILE_NAME is not 'auto', idling.")
+        try:
Evidence
video_recorder.py computes per_session_mode from SE_VIDEO_FILE_NAME only; however video.sh selects
the effective mode from FILE_NAME first, and its fixed-filename branch starts ffmpeg without
checking SE_RECORD_VIDEO or per-session capability. README explicitly documents FILE_NAME as an
override, so the controller and runner disagree in a supported configuration.

Video/video_recorder.py[86-97]
Video/video.sh[3-15]
Video/video.sh[234-247]
README.md[707-734]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`Video/video_recorder.py` decides whether to idle/start `video.sh` based on `SE_VIDEO_FILE_NAME` only. But `video.sh` uses `FILE_NAME` as a higher-priority override for the effective file name, which also changes whether it runs fixed-file recording vs per-session recording. This can cause recording to run when `SE_RECORD_VIDEO=false` (if `FILE_NAME` is fixed) or cause the recorder to idle when `video.sh` would run in per-session mode (if `FILE_NAME=auto`).

## Issue Context
- `video.sh` picks `VIDEO_FILE_NAME=${FILE_NAME:-$SE_VIDEO_FILE_NAME}`.
- `video_recorder.py` currently checks only `SE_VIDEO_FILE_NAME == "auto"`.
- Fixed-file branch in `video.sh` starts ffmpeg without consulting `SE_RECORD_VIDEO` or per-session capability.

## Fix Focus Areas
- Video/video_recorder.py[86-98]
- Video/video.sh[234-249]

## Suggested approach
1. In `_run_shell_recorder()`, compute an **effective** configured filename using the same precedence as `video.sh` (e.g., `FILE_NAME` then `SE_VIDEO_FILE_NAME`), and derive `per_session_mode` from that effective value (ideally case-insensitive via `.strip().lower() == "auto"`).
2. Ensure that when the **effective** filename is fixed (not `auto`) and `SE_RECORD_VIDEO=false`, the recorder does not start `video.sh` (idle instead), even if `SE_VIDEO_FILE_NAME` is `auto`.
3. (Optional hardening) Add a `SE_RECORD_VIDEO` guard in `video.sh` fixed-file branch to prevent accidental always-on recording when global recording is disabled.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Uploader busy-waits when disabled 🐞 Bug ➹ Performance
Description
The uploader is now always started by supervisord, and in shell mode it runs upload.sh even when
SE_VIDEO_UPLOAD_ENABLED is false. Since video.sh only creates the upload FIFO when uploads are
enabled, upload.sh loops forever (sleeping 1s) waiting for a pipe that will never exist, wasting
resources.
Code

Video/uploader.conf[R5-8]

+autostart=true
startsecs=0
-autorestart=%(ENV_SE_VIDEO_UPLOAD_ENABLED)s
+autorestart=true
stopsignal=TERM
Evidence
uploader.conf now unconditionally autostarts and autorestarts the uploader process. In
non-event-driven mode, video_uploader.py always launches upload.sh, which loops waiting for a named
pipe; but video.sh creates that pipe only when VIDEO_UPLOAD_ENABLED/SE_VIDEO_UPLOAD_ENABLED is
true—so when uploads are disabled, the uploader spins indefinitely.

Video/uploader.conf[1-9]
Video/video_uploader.py[17-36]
Video/video.sh[66-77]
Video/upload.sh[95-100]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`Video/uploader.conf` now starts the uploader unconditionally. In shell mode (`SE_VIDEO_EVENT_DRIVEN=false`), `video_uploader.py` always executes `upload.sh`, but `upload.sh` waits in a loop for a FIFO that is only created by `video.sh` when uploads are enabled. When `SE_VIDEO_UPLOAD_ENABLED=false`, this becomes an infinite busy-wait loop.

## Issue Context
- `upload.sh` waits for `${UPLOAD_PIPE_FILE}` with a 1-second polling loop.
- `video.sh` only calls `mkfifo` when `VIDEO_UPLOAD_ENABLED=true`.
- PR changed supervisord config so uploader always starts.

## Fix Focus Areas
- Video/uploader.conf[1-9]
- Video/video_uploader.py[17-36]
- Video/upload.sh[95-101]
- Video/video.sh[66-77]

## Suggested fixes (pick one)
1. **Restore conditional supervisord start**: revert to `autostart=%(ENV_SE_VIDEO_UPLOAD_ENABLED)s` and `autorestart=%(ENV_SE_VIDEO_UPLOAD_ENABLED)s`.
2. **Add runtime gating in `video_uploader.py`** (recommended if you must keep autostart=true):
  - If `SE_VIDEO_EVENT_DRIVEN=false` and upload is effectively disabled (`SE_VIDEO_UPLOAD_ENABLED!=true` and/or destination prefix empty depending on desired semantics), do not run `upload.sh`; instead idle with a long sleep (or exit cleanly and set supervisord `autorestart=false`).
3. **Make `upload.sh` block without polling** when disabled (e.g., detect disabled config and sleep longer), to avoid 1-second wakeups forever.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

Comment thread Video/video_recorder.py
Comment on lines +92 to +97
try:
while True:
time.sleep(60)
except KeyboardInterrupt:
pass
return
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. keyboardinterrupt swallowed in idle 📘 Rule violation ☼ Reliability

In the new idle path, KeyboardInterrupt is caught and ignored, causing SIGINT to exit cleanly
instead of preserving default interrupt termination semantics. This violates the requirement that
pre-async SIGINT handling must not be swallowed, and can misclassify external shutdown as a normal
exit.
Agent Prompt
## Issue description
`Video/video_recorder.py` introduces an idle loop that catches `KeyboardInterrupt` and ignores it, which changes SIGINT behavior from default interrupt termination to a clean/normal exit.

## Issue Context
Compliance requires that pre-async SIGINT termination semantics are preserved (i.e., SIGINT should not be swallowed/misclassified as a normal exit).

## Fix Focus Areas
- Video/video_recorder.py[92-97]

## Suggested direction
- Remove the `try/except KeyboardInterrupt` block entirely, or
- Re-raise `KeyboardInterrupt` after any necessary logging/cleanup, or
- Explicitly exit with an interrupt-like code (e.g., `raise` or `sys.exit(130)`) so termination semantics are preserved.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment thread Video/video_recorder.py
Comment on lines +87 to +92
record_video = os.environ.get("SE_RECORD_VIDEO", "true").lower() == "true"
per_session_mode = os.environ.get("SE_VIDEO_FILE_NAME", "") == "auto"

if not record_video and not per_session_mode:
print("[video.recorder] - SE_RECORD_VIDEO is disabled and SE_VIDEO_FILE_NAME is not 'auto', idling.")
try:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

2. File_name bypasses recorder gating 🐞 Bug ≡ Correctness

In shell mode, video_recorder._run_shell_recorder() decides whether to idle using only
SE_VIDEO_FILE_NAME, but video.sh uses FILE_NAME to override the effective filename/mode. This
mismatch can make recording start in fixed-file mode even with SE_RECORD_VIDEO=false (bypassing
capability-based gating) or make the recorder idle when video.sh would run per-session mode.
Agent Prompt
## Issue description
`Video/video_recorder.py` decides whether to idle/start `video.sh` based on `SE_VIDEO_FILE_NAME` only. But `video.sh` uses `FILE_NAME` as a higher-priority override for the effective file name, which also changes whether it runs fixed-file recording vs per-session recording. This can cause recording to run when `SE_RECORD_VIDEO=false` (if `FILE_NAME` is fixed) or cause the recorder to idle when `video.sh` would run in per-session mode (if `FILE_NAME=auto`).

## Issue Context
- `video.sh` picks `VIDEO_FILE_NAME=${FILE_NAME:-$SE_VIDEO_FILE_NAME}`.
- `video_recorder.py` currently checks only `SE_VIDEO_FILE_NAME == "auto"`.
- Fixed-file branch in `video.sh` starts ffmpeg without consulting `SE_RECORD_VIDEO` or per-session capability.

## Fix Focus Areas
- Video/video_recorder.py[86-98]
- Video/video.sh[234-249]

## Suggested approach
1. In `_run_shell_recorder()`, compute an **effective** configured filename using the same precedence as `video.sh` (e.g., `FILE_NAME` then `SE_VIDEO_FILE_NAME`), and derive `per_session_mode` from that effective value (ideally case-insensitive via `.strip().lower() == "auto"`).
2. Ensure that when the **effective** filename is fixed (not `auto`) and `SE_RECORD_VIDEO=false`, the recorder does not start `video.sh` (idle instead), even if `SE_VIDEO_FILE_NAME` is `auto`.
3. (Optional hardening) Add a `SE_RECORD_VIDEO` guard in `video.sh` fixed-file branch to prevent accidental always-on recording when global recording is disabled.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment thread Video/uploader.conf
Comment on lines +5 to 8
autostart=true
startsecs=0
autorestart=%(ENV_SE_VIDEO_UPLOAD_ENABLED)s
autorestart=true
stopsignal=TERM
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

3. Uploader busy-waits when disabled 🐞 Bug ➹ Performance

The uploader is now always started by supervisord, and in shell mode it runs upload.sh even when
SE_VIDEO_UPLOAD_ENABLED is false. Since video.sh only creates the upload FIFO when uploads are
enabled, upload.sh loops forever (sleeping 1s) waiting for a pipe that will never exist, wasting
resources.
Agent Prompt
## Issue description
`Video/uploader.conf` now starts the uploader unconditionally. In shell mode (`SE_VIDEO_EVENT_DRIVEN=false`), `video_uploader.py` always executes `upload.sh`, but `upload.sh` waits in a loop for a FIFO that is only created by `video.sh` when uploads are enabled. When `SE_VIDEO_UPLOAD_ENABLED=false`, this becomes an infinite busy-wait loop.

## Issue Context
- `upload.sh` waits for `${UPLOAD_PIPE_FILE}` with a 1-second polling loop.
- `video.sh` only calls `mkfifo` when `VIDEO_UPLOAD_ENABLED=true`.
- PR changed supervisord config so uploader always starts.

## Fix Focus Areas
- Video/uploader.conf[1-9]
- Video/video_uploader.py[17-36]
- Video/upload.sh[95-101]
- Video/video.sh[66-77]

## Suggested fixes (pick one)
1. **Restore conditional supervisord start**: revert to `autostart=%(ENV_SE_VIDEO_UPLOAD_ENABLED)s` and `autorestart=%(ENV_SE_VIDEO_UPLOAD_ENABLED)s`.
2. **Add runtime gating in `video_uploader.py`** (recommended if you must keep autostart=true):
   - If `SE_VIDEO_EVENT_DRIVEN=false` and upload is effectively disabled (`SE_VIDEO_UPLOAD_ENABLED!=true` and/or destination prefix empty depending on desired semantics), do not run `upload.sh`; instead idle with a long sleep (or exit cleanly and set supervisord `autorestart=false`).
3. **Make `upload.sh` block without polling** when disabled (e.g., detect disabled config and sleep longer), to avoid 1-second wakeups forever.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant