Skip to content

[#37930][Runners] Reap child processes in ProcessManager to prevent zombie accumulation#37932

Merged
Abacn merged 2 commits intoapache:masterfrom
andresti:fix-process-manager-zombie-reaping
Mar 25, 2026
Merged

[#37930][Runners] Reap child processes in ProcessManager to prevent zombie accumulation#37932
Abacn merged 2 commits intoapache:masterfrom
andresti:fix-process-manager-zombie-reaping

Conversation

@andresti
Copy link
Contributor

@andresti andresti commented Mar 24, 2026

Summary

Fixes #37930

ProcessManager.stopProcess() calls destroy()/destroyForcibly() but never Process.waitFor(), so terminated child processes remain as zombies in the kernel process table.

On long-running Flink TaskManagers with --environment_type=PROCESS, expansion service processes accumulate as zombies over time (176+ observed on production hosts). Container-level init systems (dumb-init, tini) cannot help because
the zombies are children of the still-running TaskManager — only the parent can reap them.

Changes

Adds process.waitFor() calls in:

  • stopProcess() — after the destroy/destroyForcibly sequence
  • killAllProcesses() — after destroyForcibly in the shutdown hook path

Testing

Existing ProcessManagerTest suite passes. The zombie issue is only observable at the OS level over time and cannot be meaningfully unit-tested — it was confirmed by monitoring production Flink pods.


Thank you for your contribution! Follow this checklist to help us incorporate your contribution quickly and easily:

  • Mention the appropriate issue in your description (for example: addresses #123), if applicable. This will automatically add a link to the pull request in the issue. If you would like the issue to automatically close on merging the pull request, comment fixes #<ISSUE NUMBER> instead.
  • Update CHANGES.md with noteworthy changes.
  • If this contribution is large, please file an Apache Individual Contributor License Agreement.

See the Contributor Guide for more tips on how to make review process smoother.

To check the build health, please visit https://github.com/apache/beam/blob/master/.test-infra/BUILD_STATUS.md

…vent zombie accumulation

ProcessManager.stopProcess() calls destroy()/destroyForcibly() to terminate
child processes, but never calls Process.waitFor() to collect the exit status.
On POSIX systems, this means the terminated child process entry remains in the
kernel process table as a zombie (state Z/defunct) until the parent process
itself exits.

In long-running environments like Flink TaskManagers using
--environment_type=PROCESS, the expansion service processes are repeatedly
spawned and stopped but never reaped. Over time this leads to significant
zombie accumulation (176+ observed on production hosts).

The fix adds process.waitFor() calls after process termination in:
- stopProcess(): after the destroy/destroyForcibly sequence
- killAllProcesses(): after destroyForcibly in the shutdown hook path

Fixes apache#37930
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request resolves a critical issue where child processes were not being properly reaped, leading to an accumulation of zombie processes in long-running Flink TaskManagers. By adding process.waitFor() calls, the changes ensure that terminated processes are removed from the kernel process table, preventing resource exhaustion and improving system stability.

Highlights

  • Zombie Process Prevention: This PR addresses the accumulation of zombie processes in long-running Flink TaskManagers by ensuring that child processes are properly reaped after termination.
  • ProcessManager Updates: The changes introduce process.waitFor() calls in stopProcess() and killAllProcesses() to collect the exit status of terminated child processes.
  • Testing: While the existing test suite passes, the fix was confirmed by monitoring production Flink pods due to the difficulty of unit-testing zombie process accumulation.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@andresti andresti marked this pull request as ready for review March 24, 2026 15:00
@github-actions
Copy link
Contributor

Checks are failing. Will not request review until checks are succeeding. If you'd like to override that behavior, comment assign set of reviewers

Copy link
Contributor

@Abacn Abacn left a comment

Choose a reason for hiding this comment

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

Thanks for reporting this issue and the fix!

@Abacn
Copy link
Contributor

Abacn commented Mar 25, 2026

Different tests failed in two attempts

Run 1 (https://github.com/apache/beam/runs/68383107343):

testHotKeyLoggingNotEnabled[0: [streamingEngine=false]] (org.apache.beam.runners.dataflow.worker.StreamingDataflowWorkerTest) failed

testBasic[0: [streamingEngine=false]] (org.apache.beam.runners.dataflow.worker.StreamingDataflowWorkerTest) failed

testHotKeyLogging[0: [streamingEngine=false]] (org.apache.beam.runners.dataflow.worker.StreamingDataflowWorkerTest) failed

testBasicHarness[0: [streamingEngine=false]] (org.apache.beam.runners.dataflow.worker.StreamingDataflowWorkerTest) failed

All are StreamingDataflowWorkerTest cc:

Run 2: testMultipleClientsFailingIsHandledGracefullyByServer (org.apache.beam.runners.fnexecution.logging.GrpcLoggingServiceTest) failed

Not related to this change. Merging for now.

@Abacn Abacn merged commit 7431dea into apache:master Mar 25, 2026
19 of 22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: ProcessManager does not reap child processes, causing zombie accumulation on long-running Flink deployments

2 participants