Skip to content

fix: properly wait for Ryuk startup when reusing reaper - #3761

Merged
mdelapenya merged 3 commits into
testcontainers:mainfrom
karsov:fix/issue-3743
Jul 15, 2026
Merged

fix: properly wait for Ryuk startup when reusing reaper#3761
mdelapenya merged 3 commits into
testcontainers:mainfrom
karsov:fix/issue-3743

Conversation

@karsov

@karsov karsov commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

Adds a wait.ForLog("Started") when reusing an already running reaper DockerContainer.

Why is it important?

Without the additional wait condition, when multiple concurrent tests are run in different packages, only the package where the reaper is created (and not reused) waits properly for the Ryuk startup. For all the other packages the connection to the reaper container is attempted before Ryuk is ready and it fails with errors like the following:

2026/06/29 11:58:58 Reaper handshake failed: read ack: read tcp [::1]:45156->[::1]:33074: read: connection reset by peer

or

2026/06/29 12:09:49 Reaper handshake failed: read ack: EOF

Without connection, the reaper does not know it should wait for the tests in that packages to finish before cleaning up their containers, leading to failing tests.

More details in #3743 .

Related issues

How to test this PR

As agreed in #3743 , first I'm adding only the commit updating the tests to demonstrate the failure, so we can run the CI on it to expose the failure, and then I'll add the fix itself.

@karsov
karsov requested a review from a team as a code owner July 6, 2026 09:10
@netlify

netlify Bot commented Jul 6, 2026

Copy link
Copy Markdown

Deploy Preview for testcontainers-go ready!

Name Link
🔨 Latest commit dc22191
🔍 Latest deploy log https://app.netlify.com/projects/testcontainers-go/deploys/6a4b8f61dccbbe00083c9841
😎 Deploy Preview https://deploy-preview-3761--testcontainers-go.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ec081ae9-3fb9-49a9-9ebe-10cb38070fb3

📥 Commits

Reviewing files that changed from the base of the PR and between 7bcb99e and dc22191.

📒 Files selected for processing (1)
  • reaper.go

Summary by CodeRabbit

  • Tests
    • Strengthened coverage for Reaper startup by validating that the connection handshake succeeds during concurrent instance reuse.
    • Improved test reliability by using a timed connection attempt, helping detect connection/handshake issues earlier.
  • Bug Fixes
    • Improved readiness detection when reusing an existing Reaper container by ensuring both the startup signal and port readiness are confirmed before proceeding.

Walkthrough

This change tightens Reaper reuse readiness by waiting for both startup log output and port availability, and extends the concurrent reuse test to dial the Reaper endpoint and verify the handshake succeeds.

Changes

Reaper readiness and handshake validation

Layer / File(s) Summary
Reuse readiness gate
reaper.go
fromContainer now waits for both the "Started" log line and the exposed port before treating a reused Reaper container as ready.
Handshake test helper
reaper_test.go
Adds net, defines reaperConnect to dial reaper.Endpoint and run reaper.handshake(conn), and calls it from TestReaper_ReuseRunning for each concurrent instance.

Estimated code review effort: 2 (Simple) | ~10 minutes

Poem

I hop to check the Reaper’s door,
A log, a port, and handshake lore.
If all is well, I nibble cheer,
And tests stay calm both far and near. 🐇

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title references the added handshake assertion in the reaper reuse test, which is a real part of the change.
Description check ✅ Passed The description matches the reuse-path readiness fix and the handshake failure scenario in the changeset.
Linked Issues check ✅ Passed The changes add readiness verification on the reuse path and test the handshake, matching #3743's requirements.
Out of Scope Changes check ✅ Passed The PR stays focused on reaper readiness and handshake behavior, with no obvious unrelated changes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@reaper_test.go`:
- Around line 532-547: The test helper reaperConnect is using require.NoError
with a message that includes %w, but msgAndArgs are formatted with fmt.Sprintf
rather than error-wrapping. Update the dial assertion to use a normal error
formatting verb so the underlying dial failure is printed correctly, and keep
the same context around reaper.Endpoint and the handshake call for debugging.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ee8bc777-7038-4693-be82-4aaea700776c

📥 Commits

Reviewing files that changed from the base of the PR and between 43c9639 and 2177d36.

📒 Files selected for processing (1)
  • reaper_test.go

Comment thread reaper_test.go
@mdelapenya mdelapenya added the bug An issue with the library label Jul 15, 2026
@mdelapenya mdelapenya self-assigned this Jul 15, 2026

@mdelapenya mdelapenya 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.

LGTM, thanks!

@mdelapenya
mdelapenya merged commit c92ea61 into testcontainers:main Jul 15, 2026
225 checks passed
@karsov karsov changed the title fix: add handshake assertion in TestReaper_ReuseRunning fix: Properly wait for Ryuk startup when reusing reaper Jul 15, 2026
@karsov karsov changed the title fix: Properly wait for Ryuk startup when reusing reaper fix: properly wait for Ryuk startup when reusing reaper Jul 15, 2026
@claude claude Bot mentioned this pull request Aug 17, 2026
1 task
thockin pushed a commit to agent-substrate/substrate that referenced this pull request Aug 27, 2026
Part of #1230

When reusing an already-running Ryuk reaper, testcontainers-go v0.43.0
waits only for its Docker port mapping. Docker exposes that port before
Ryuk is listening, so a second package can connect too early and lose
the handshake with `read ack: EOF`. That is
[testcontainers-go#3743](testcontainers/testcontainers-go#3743);
v0.44.0 also waits for the reaper's `Started` log line
([#3761](testcontainers/testcontainers-go#3761)).

A package whose handshake fails is not counted as a Ryuk client but its
containers still carry the shared session label, so another package
exiting can delete a database that is still in use — the failure
reported in #1230.

## Scope

This helps local runs, where the reaper stays on. **It does not fix CI
on its own**, so it is deliberately separate from #1235, which disables
the reaper for `run-tests`.

Measured on a 4-core Linux VM with cold build caches, which staggers
package start times the way CI does:

```
v0.43.0, 3 rounds   handshake failures in 3/3 rounds; one round cascaded
v0.44.0, 3 rounds   no handshake failures; database tests still unavailable in 3/3 rounds
```

Under v0.44.0 the failures move to `wait for reaper <id>: context
deadline exceeded` — a late package finds a reaper that is already
shutting down, and one readiness probe (`defaultStartupTimeout`, 60s)
outlives the whole reaper retry budget (`MaxElapsedTime`, 20s), so the
retry loop never gets a second attempt. The remaining fail-open behind
all of this is
[#3827](testcontainers/testcontainers-go#3827),
still open upstream.

## Diff size

Four lines of `go.mod`. The rest is `go mod vendor` output: v0.44.0
pulls newer `moby/client`, `gopsutil`, and `otelhttp`, and `otelhttp`
moves `otel/semconv` from v1.39.0 to v1.41.0. Insertions and deletions
nearly cancel because most of it is a directory swap and one generated
`httpsnoop` file being merged into another.

```
go.mod, go.sum      62 lines
vendor/             61 files, 17356 +/17490 -
```

`hack/verify/go-modules.sh`, `licenses.sh`, `boilerplate.sh`, and
`gofmt.sh` all pass; `go test -race ./cmd/ateapi/...` is green with no
silently skipped database tests.

---

- [x] Tests pass
- [x] Appropriate changes to documentation are included in the PR
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug An issue with the library

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Premature container reaping under concurrent multi-package go test ./...

2 participants