Skip to content

fix(env): atexit cleanup for DockerEnvironment - #881

Open
vkandbro wants to merge 2 commits into
SWE-agent:mainfrom
vkandbro:fix/docker-atexit-cleanup
Open

fix(env): atexit cleanup for DockerEnvironment#881
vkandbro wants to merge 2 commits into
SWE-agent:mainfrom
vkandbro:fix/docker-atexit-cleanup

Conversation

@vkandbro

Copy link
Copy Markdown

Problem

The DockerEnvironment.cleanup() method was only called via __del__, which is not guaranteed to execute on abnormal exit (Ctrl+C, interpreter crash). This could leave Docker containers running as zombie processes.

Solution

Register atexit.register(self.cleanup) in __init__, which guarantees execution on normal Python exit. Add a _cleaned flag to make cleanup() idempotent for the case where both atexit and __del__ fire.

Changes

  • src/minisweagent/environments/docker.py: Add atexit.register, add _cleaned idempotency flag
  • tests/environments/test_docker_cleanup.py: New tests for cleanup idempotency

Testing

  • test_cleanup_idempotent: Verifies multiple cleanup() calls do not raise
  • test_cleaned_flag: Verifies _cleaned is set after cleanup

Notes for Reviewer

  • No API changes — all existing usage patterns remain compatible
  • atexit is stdlib, no new dependencies
  • _cleaned flag protects against the atexit + __del__ double-call edge case

vkandbro and others added 2 commits June 29, 2026 14:19
…) idempotent

The cleanup() method was only called via __del__, which is not guaranteed on abnormal exit. Add atexit registration to ensure Docker containers are cleaned up.

- Add atexit.register in __init__
- Add _cleaned flag for idempotent cleanup
- Add tests for cleanup idempotency

@klieret klieret left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Oh, you're right, this is better! But should we remove the __del__ then?

cmd = f"(timeout 60 {self.config.executable} stop {self.container_id} || {self.config.executable} rm -f {self.container_id}) >/dev/null 2>&1 &"
subprocess.Popen(cmd, shell=True)

def __del__(self):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

could we remove this then?

Copilot AI 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.

Pull request overview

This PR hardens DockerEnvironment resource cleanup by ensuring container teardown runs on normal interpreter exit (via atexit) and making cleanup calls idempotent to avoid double-cleanup across atexit and __del__.

Changes:

  • Register DockerEnvironment.cleanup() with atexit during initialization.
  • Add a _cleaned flag to make cleanup() idempotent.
  • Add slow integration tests validating repeated cleanup() calls and _cleaned flag behavior.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
src/minisweagent/environments/docker.py Registers cleanup() with atexit and adds _cleaned idempotency guard for container teardown.
tests/environments/test_docker_cleanup.py Adds slow integration tests to validate idempotent cleanup and _cleaned state changes.

Comment on lines +158 to +161
if self._cleaned:
return
self._cleaned = True
if getattr(self, "container_id", None) is not None:
@codecov

codecov Bot commented Jun 29, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 85.71429% with 1 line in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/minisweagent/environments/docker.py 85.71% 0 Missing and 1 partial ⚠️
Files with missing lines Coverage Δ
src/minisweagent/environments/docker.py 92.85% <85.71%> (-0.74%) ⬇️

... and 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@klieret

klieret commented Jul 2, 2026

Copy link
Copy Markdown
Member

OK so the bigger problem here is that right now basically we rely on python garbage collection to clean up docker containers. Once the env is GCd __del__ is called which cleans up the container. However, with the atexit call, we'd now keep a reference to this object, so GC will never trigger anymore. Meaning that the automatic cleanup is no longer active.

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.

3 participants