Skip to content

Stop the frontend tree when headless reflex run exits - #7328

Merged
masenf merged 20 commits into
reflex-dev:mainfrom
flcrom:fix/headless-frontend-tree-shutdown
Oct 5, 2026
Merged

masenf merged 20 commits into
reflex-dev:mainfrom
flcrom:fix/headless-frontend-tree-shutdown

Conversation

@flcrom

@flcrom flcrom commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

Closes #6980.

When the run unwinds, _run_dev terminates the frontend process. The frontend stays in the CLI process group, so a SIGKILL of the group also stops it. A frontend that launches after shutdown starts is terminated at launch. On POSIX, frontend-only mode exits cleanly on SIGTERM. This replaces #7209 with a smaller change.

Tests: no-TTY subprocess cases for SIGTERM, SIGINT and SIGKILL in frontend-only and full-stack mode, plus a failing frontend task, a normal backend return and a late frontend launch. Windows descendant cleanup is not changed.

Review in cubic

@flcrom
flcrom requested a review from a team as a code owner September 25, 2026 09:51

@cubic-dev-ai cubic-dev-ai Bot left a comment •

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.

All reported issues were addressed across 6 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread reflex/utils/processes.py Outdated
Comment thread tests/units/test_reflex.py Outdated
Comment thread tests/units/utils/test_processes.py Outdated
@greptile-apps

greptile-apps Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 4/5

[High risk] Changes process lifecycle and signal handling in the dev runner.

The PR is not yet safe to merge because frontend-only SIGINT still exits unsuccessfully, and the outstanding repository documentation requirements and new test-helper requirement remain.

Findings

  1. P1 SIGINT no longer exits cleanly ▶
  2. P2 Repeated subprocess test setup ▶
  3. P2 Signal handlers lack required docstrings ▶
  4. P2 Polling duration lacks explanation ▶

Summary

The PR stops the development frontend when reflex run unwinds, handles late frontend launches, and adds headless signal and shutdown tests.

  • Frontend-only runs wait for their frontend task and handle POSIX SIGTERM.
  • The new subprocess tests cover normal exit, failure, late launch, and signals without a TTY.

Reviews (13) · Last reviewed commit: "Merge remote-tracking branch 'upstream/m..."

Comment thread reflex/utils/processes.py Outdated
Comment thread reflex/utils/processes.py Outdated
@codspeed

codspeed Bot commented Sep 25, 2026 •

Copy link
Copy Markdown

Merging this PR will improve performance by 4.36%

⚠️ Different runtime environments detected

Some benchmarks with significant performance changes were compared across different runtime environments,
which may affect the accuracy of the results.

Open the report in CodSpeed to investigate

⚡ 1 improved benchmark
✅ 146 untouched benchmarks
⏩ 17 skipped benchmarks1

Performance Changes

Benchmark BASE HEAD Efficiency
⚡ test_route_argument_extraction 120.8 µs 115.8 µs +4.36%

Tip

Curious why performance improved? Comment @codspeedbot explain why performance improved on this PR, or directly use the CodSpeed MCP with your agent.


Comparing flcrom:fix/headless-frontend-tree-shutdown (2a8c010) with main (5aafe47)

Open in CodSpeed

Footnotes

  1. 17 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports. ↩

Comment thread tests/units/utils/test_processes.py Outdated
@flcrom

flcrom commented Sep 25, 2026

Copy link
Copy Markdown
Contributor Author

Could a maintainer rerun the Ubuntu 3.10 unit-test job? The Redis-enabled stage failed in test_oplock_contention_racers[0] in tests/units/istate/manager/test_redis.py, which this PR doesn't change. The other checks passed, and I don't have permission to rerun this upstream job. Thank you.

Comment thread reflex/utils/exec.py Outdated
Comment thread reflex/utils/processes.py Outdated
Comment thread reflex/utils/processes.py Outdated
Comment thread reflex/reflex.py Outdated
Comment thread reflex/reflex.py Outdated

@FarhanAliRaza FarhanAliRaza left a comment

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.

I tested this PR with a small counter app, on this branch and on its merge base with main. A script started reflex run in its own session, with no TTY. It waited for the frontend and the backend, then sent a signal. After each signal, it recorded the processes that survived and the ports that stayed bound.

On main, SIGTERM and SIGINT did not stop the run. In frontend-only mode, SIGTERM stopped the Python process, but bun and node continued to run. On this branch, all of these cases exit with code 0, and no processes survive. The fix for #6980 works.

I also tested Ctrl+C in a PTY, SIGHUP, and SIGKILL of the process group. Ctrl+C works on both branches. SIGHUP hangs on both branches. SIGKILL of the process group is a regression: see the inline comments. In a browser, the app loads, state updates work, and hot reload works. The unit tests in this PR pass.

The requested changes are in the inline comments.

Comment thread reflex/reflex.py
@flcrom

flcrom commented Sep 28, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the detailed review. I removed start_new_session and the process-group registry, moved frontend cleanup to _run_dev using exec.frontend_process.terminate(), and kept the frontend-only handler to SIGTERM. The SIGKILL process-group regression now has a subprocess test, red before the fix and green after. The unit suite passed locally in four splits (9,852 passed, 19 skipped); ruff and source/changed-file pyright passed. CI is running on the latest head.

Comment thread reflex/utils/processes.py
Comment thread reflex/reflex.py
Comment thread tests/units/test_reflex.py
Comment thread tests/units/test_reflex.py

@cubic-dev-ai cubic-dev-ai Bot left a comment •

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.

1 issue found across 5 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="news/7328.bugfix.md">

<violation number="1" location="news/7328.bugfix.md:1">
P3: This PR now ships two news fragments for the same change. news/6980.bugfix.md (added in an earlier revision, named after the issue rather than the PR) is still present and its text — "stops its development frontend process group on shutdown" — describes the start_new_session approach that was removed in this PR, so the release changelog would get two near-duplicate bullets, one contradicting the shipped behavior. Delete news/6980.bugfix.md and keep this fragment.</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread tests/units/test_reflex.py Outdated
Comment thread news/7328.bugfix.md
Comment thread tests/units/test_reflex.py

@cubic-dev-ai cubic-dev-ai Bot left a comment •

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.

All reported issues were addressed across 4 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread reflex/reflex.py Outdated
Comment thread tests/units/test_reflex.py

@cubic-dev-ai cubic-dev-ai Bot left a comment •

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.

All reported issues were addressed across 2 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread tests/units/test_reflex.py
@flcrom

flcrom commented Sep 29, 2026

Copy link
Copy Markdown
Contributor Author

The follow-up commits through 36c0b2a cover the late-start/teardown race as well as the five review points. Could you take another look?

@FarhanAliRaza
FarhanAliRaza force-pushed the fix/headless-frontend-tree-shutdown branch from 6596431 to 8c06ecd Compare October 1, 2026 19:24
# Conflicts:
#	reflex/reflex.py
#	tests/units/test_reflex.py
Comment thread tests/units/test_reflex.py
@masenf masenf added the on deck PRs lined up to review / merge next label Oct 5, 2026
@masenf masenf added this to the v0.10.x milestone Oct 5, 2026
@masenf
masenf merged commit eb14860 into reflex-dev:main Oct 5, 2026
158 of 201 checks passed
FarhanAliRaza pushed a commit to FarhanAliRaza/reflex that referenced this pull request Oct 5, 2026
tests/units/test_reflex.py: kept main's reflex-dev#7328 frontend-teardown tests, then this branch's test_compile_app_sets_start_method_before_compile_pool; both sides' imports kept.

Claude-Session: https://claude.ai/code/session_01VDzz2un9mtjmCY24zSGmca
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

on deck PRs lined up to review / merge next

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Backgrounded/no-TTY reflex run ignores SIGTERM/SIGINT — requires SIGKILL of the process group

3 participants