Skip to content

feat: allow overriding the session ID - #3051

Merged
mdelapenya merged 6 commits into
testcontainers:mainfrom
bckground:reuse-reaper
Aug 7, 2026
Merged

feat: allow overriding the session ID#3051
mdelapenya merged 6 commits into
testcontainers:mainfrom
bckground:reuse-reaper

Conversation

@jcmfernandes

@jcmfernandes jcmfernandes commented Mar 22, 2025

Copy link
Copy Markdown
Contributor

What does this PR do?

Makes the session ID configurable, allowing for long-running sessions.

Why is it important?

Speaking of my use-case, Apache Pulsar takes a long time to boot, so I wanted testcontainers to boot it up, eventually take it down, but allow me to use the same container across several runs. This wasn't the case, since I was getting a new reaper running on every test run. I wanted a rolling-window behavior, hence this change.

Related issues

Follow-ups

Update the documentation.

@netlify

netlify Bot commented Mar 22, 2025

Copy link
Copy Markdown

Deploy Preview for testcontainers-go ready!

Name Link
🔨 Latest commit d3faef8
🔍 Latest deploy log https://app.netlify.com/projects/testcontainers-go/deploys/6a747281036c68000818b1b5
😎 Deploy Preview https://deploy-preview-3051--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.

@jcmfernandes jcmfernandes changed the title Reuse reaper feat: allow reusing the reaper Mar 22, 2025
@jcmfernandes
jcmfernandes marked this pull request as ready for review March 22, 2025 13:39
@jcmfernandes
jcmfernandes requested a review from a team as a code owner March 22, 2025 13:39
@kiview

kiview commented Aug 18, 2025

Copy link
Copy Markdown
Member

Hey @jcmfernandes, I am actually surprised your setup doesn't work with the current Test Session Semantics.

Also, your change doesn't take the parent PID into account anymore, so it would be a breaking change for downstream integrations, that rely on the current session ID semantics.

@jcmfernandes

Copy link
Copy Markdown
Contributor Author

Hey @jcmfernandes, I am actually surprised your setup doesn't work with the current Test Session Semantics.

Also, your change doesn't take the parent PID into account anymore, so it would be a breaking change for downstream integrations, that rely on the current session ID semantics.

Thanks for getting back to me.

Without these changes, every go test ./... run create a new instance of the reaper, and I'm not alone (#2804).

As stated in the PR description:

Regarding point 3, I must admit that I don't understand the advantages of the hashing logic I ended up deleting. I'm happy to revert it, though.

I'm happy to revert those changes, but so far, setting the session ID myself (through an env var) has been the only solution that worked for me.

@kiview

kiview commented Aug 18, 2025

Copy link
Copy Markdown
Member

Without these changes, every go test ./... run create a new instance of the reaper

Alright, that is how it is supposed to work.
But what it sounds to me from what you are trying to achieve, it sounds you need Reusable Containers.

Either way, the semantics around sessions IDs and cleanup behavior are fairly involved. I'd suggest to not proceed with this work without specifically syncing with @mdelapenya and @stevenh on the design.

@jcmfernandes

Copy link
Copy Markdown
Contributor Author

Without these changes, every go test ./... run create a new instance of the reaper

Alright, that is how it is supposed to work. But what it sounds to me from what you are trying to achieve, it sounds you need Reusable Containers.

Either way, the semantics around sessions IDs and cleanup behavior are fairly involved. I'd suggest to not proceed with this work without specifically syncing with @mdelapenya and @stevenh on the design.

Thanks for the pointers. @mdelapenya and @stevenh, your input is very much welcome.

But what it sounds to me from what you are trying to achieve, it sounds you need Reusable Containers.

I am using a reusable container, and the container was always reused as expected; no issues there. The problem is that the reaper isn't reused because the session ID keeps changing.

@jcmfernandes

Copy link
Copy Markdown
Contributor Author

Also, your change doesn't take the parent PID into account anymore, so it would be a breaking change for downstream integrations, that rely on the current session ID semantics.

I pushed a new commit that brings back the logic I had previously removed. This shouldn't break things for anyone anymore.

@stevenh

stevenh commented Aug 18, 2025

Copy link
Copy Markdown
Contributor

Hi @jcmfernandes can you clarify to me the problem you're trying to solve?

Your description seems to indicate to me you want to share containers between tests due to the slow startup time?

@jcmfernandes

Copy link
Copy Markdown
Contributor Author

Hi @jcmfernandes can you clarify to me the problem you're trying to solve?

Your description seems to indicate to me you want to share containers between tests due to the slow startup time?

Hi @stevenh! Correct. In other words, I want:

  1. Reusable containers (all good!)
  2. Reusable reapers for reusable containers (not good)

Copying from #2804, this is what I see when I enable reusable containers:

CONTAINER ID  IMAGE                                                  COMMAND     CREATED             STATUS             PORTS                                                                   NAMES
b551cb564516  docker.io/testcontainers/ryuk:0.8.1                    /bin/ryuk   2 minutes ago       Up 2 minutes       0.0.0.0:39033->8080/tcp, 8080/tcp                                       reaper_42d84025974814469f367f10224b4657f7ad888e2a5d827e76703f06292c39ec
5a7876b38a26  docker.io/mysql:8.0.36                                 mysqld      2 minutes ago       Up 2 minutes       0.0.0.0:42559->3306/tcp, 0.0.0.0:44633->33060/tcp, 3306/tcp, 33060/tcp  tests-mysql
c93fdf315582  docker.io/testcontainers/ryuk:0.8.1                    /bin/ryuk   2 minutes ago       Up 2 minutes       0.0.0.0:34995->8080/tcp, 8080/tcp                                       reaper_3ccf995c484a246a36990a92f85c3fc17ffb3912f867ba70b029aaf323f48547
e63820a62ce3  docker.io/testcontainers/ryuk:0.8.1                    /bin/ryuk   2 minutes ago       Up 2 minutes       0.0.0.0:44359->8080/tcp, 8080/tcp                                       reaper_fe49fa57fcc7031f3d1e9dbb6f305a2f4b392d1b10921d42b6a0df56e4970667
56d082f1fbbd  docker.io/testcontainers/ryuk:0.8.1                    /bin/ryuk   About a minute ago  Up About a minute  0.0.0.0:38461->8080/tcp, 8080/tcp                                       reaper_669ec11b7226f1c446fddd1a0e3f1aadfd1627687ed6adf3b5c846e66ecbe276
9922c527850c  docker.io/testcontainers/ryuk:0.8.1                    /bin/ryuk   About a minute ago  Up About a minute  0.0.0.0:34041->8080/tcp, 8080/tcp                                       reaper_74976de06285397df7d0edffbdd2e5fd284cf833f5b3de025705fbcad5e3608b
c76bcd09a892  docker.io/testcontainers/ryuk:0.8.1                    /bin/ryuk   52 seconds ago      Up 52 seconds      0.0.0.0:32785->8080/tcp, 8080/tcp                                       reaper_6e46bea7477b04a07464880892df435bdbd55753551da0d80b51d8917f4ab094
df476617ebdf  docker.io/testcontainers/ryuk:0.8.1                    /bin/ryuk   42 seconds ago      Up 42 seconds      0.0.0.0:39403->8080/tcp, 8080/tcp                                       reaper_24fdf990fc0d0ce6e34d030f619611233f7b7e714e623e1b6c635f7a85fdee4a
fc398aaabe82  docker.io/testcontainers/ryuk:0.8.1                    /bin/ryuk   27 seconds ago      Up 27 seconds      0.0.0.0:34295->8080/tcp, 8080/tcp                                       reaper_f9596c3bfefde5404c227e99286798894109b8d3b1de2fe207580a1baf340ac6
8ac0c88b5298  docker.io/testcontainers/ryuk:0.8.1                    /bin/ryuk   18 seconds ago      Up 18 seconds      0.0.0.0:42809->8080/tcp, 8080/tcp                                       reaper_8a5edab68adc986d01ff49f0774b013c3933ee8854bda319df02d26dfa233ded
64edfcfa3ec0  docker.io/testcontainers/ryuk:0.8.1                    /bin/ryuk   8 seconds ago       Up 9 seconds       0.0.0.0:35387->8080/tcp, 8080/tcp                                       reaper_3d76e1e0b630828fad795b4fcc603edaf11179da4d56148248f89862e92139d1

I want to see one reaper for the reusable container. As a side effect, having one reaper creates a “rolling window” behavior, where the reaper resets its timeout upon a new connection to the container, which is precisely what I would like to see: keep the container up and running between test runs and terminate it after the defined period of inactivity.

Am I making sense?

@kiview

kiview commented Aug 18, 2025

Copy link
Copy Markdown
Member

Oh yes, that makes absolutely sense and I believe this is more of a bug and something that Testcontainers should already handle correctly, rather than having a user to specify a session id manually.

@stevenh

stevenh commented Aug 18, 2025

Copy link
Copy Markdown
Contributor

Thanks for the confirmation @jcmfernandes.

To facilitate this are you intending to set a long ReconnectionTimeout for all containers? I ask as if so I think thats going to prevent clean up of all other containers too, which I'm not sure is your intention?

@jcmfernandes

jcmfernandes commented Aug 19, 2025

Copy link
Copy Markdown
Contributor Author

@stevenh yes, because I want to keep the testcontainer running for the entirety of my work session.

I usually start a watcher that runs tests automatically as I save changes. I want the testcontainer to boot on the first test run and to stay around for, say, one hour, waiting for new connections. Furthermore, I then want new connections to reset that timeout. Example.

  1. Run a test that starts the testcontainer at 9:05 AM with a reconnection timeout of 1 hour. Ryuk must wait for new connections until 10:05 AM, and GC the testcontainer if that doesn't happen.
  2. Run another test at 9:35 AM --> I now want ryuk to wait until 10:35 AM for new connections.

This is precisely the behavior I get by manually setting the session ID and RYUK_RECONNECTION_TIMEOUT to 1 hour. Now, I'm happy to discuss ways to make the session ID stable and auto-generated.

@stevenh

stevenh commented Aug 19, 2025

Copy link
Copy Markdown
Contributor

Thanks again for the clarification, the challenge I see with that is not only does it impact the long lived container but all containers for example:

You run a test which starts the long lived DB container as well a short lived test container. The desired behaviour is the DB container stays running between tests, but the test container itself exits after the test is run.

However in the case where the test fails and the short lived contain didn't exit as expected, with a standard ryuk setup this wouldn't be an issue as the test container would be quickly cleaned up, but with RYUK_RECONNECTION_TIMEOUT set to one hour no clean up will happen until that hour expires.

Does this make sense?

To handle this situation properly I think we'd need more fine grained control of when specific containers are cleaned up.

@jcmfernandes

Copy link
Copy Markdown
Contributor Author

Thanks for the prompt reply, @stevenh.

That's a fair concern — it seems that testcontainers is missing some kind of "group" concept to which certain GC options apply. Currently, that's a "session", and this PR won't change it. That is, I don't see how this PR makes things worse regarding your concern, and it solves an actual reported issue.

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

Hi @jcmfernandes, thanks for opening this PR, and following-up after @kiview's comments. I'm returning today after summer break, working on the open PRs/issues in the repo.

I'm not against the changes in this PR, although it introduces some breaking changes (BCs) after removing public API functions. See my comments for that. We could avoid it offering a deprecation path when/if possible, although we sometimes introduce BCs if needed.

I'd rename the PR to feat: allow overriding the sessionID and would focus on that, only. The added value if we do this is we would also enable Bazel folks to contribute their own env var for the session ID at build time. Nevertheless, we must check how the reaper behaves in that scenario. As discussed here, it's by design that the reaper is spawned just once per test session (a shell), but it's true that the design could be inconsistent with reusable containers used in multiple shells (different session IDs). Sharing state, even in tests, is a complex thing to maintain, so we probably need a more robust design for both features: reusable containers and the reaper, and it could need dedicated work on that direction.

@kiview @stevenh wdyt?

Comment thread docker.go Outdated
Comment thread config.go
@jcmfernandes

Copy link
Copy Markdown
Contributor Author

@mdelapenya thanks for your input. I modified this PR, making it focus solely on allowing devs to set the session ID, and I opened a separate PR #3269 where I delete TestcontainersConfig.

@jcmfernandes jcmfernandes changed the title feat: allow reusing the reaper feat: allow overriding the session ID Aug 26, 2025
@mdelapenya mdelapenya self-assigned this Aug 26, 2025
@mdelapenya mdelapenya added the feature New functionality or new behaviors on the existing one label Aug 26, 2025
Comment thread internal/core/bootstrap.go Outdated

@stevenh stevenh 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'm concerned calling config.Read in init could have some unintended side effects which are impossible to address, something we'll need to confirm.

Comment thread internal/core/bootstrap.go Outdated
Comment thread internal/core/bootstrap.go Outdated
@coderabbitai

coderabbitai Bot commented Nov 20, 2025

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Summary by CodeRabbit

  • New Features

    • Session identifiers are now consistently sourced from configuration, including support for the TESTCONTAINERS_SESSION_ID environment variable and a default generated session.
    • Configured session identifiers are used for container coordination, networking, status reporting, and health checks, improving consistency across related operations.
  • Tests

    • Added and updated coverage for session ID loading, environment-variable precedence, defaults, and session-dependent behavior.

Walkthrough

Session ID resolution now uses shared configuration. Configuration reads session.id, TESTCONTAINERS_SESSION_ID, or the bootstrap fallback. Container, label, Docker, reaper, and client paths consume the configured session ID.

Changes

Session ID centralization

Layer / File(s) Summary
Session ID configuration and coverage
internal/core/bootstrap/bootstrap.go, internal/config/config.go, internal/config/config_test.go
Config exposes SessionID. Configuration resolves it from properties or TESTCONTAINERS_SESSION_ID, with a bootstrap fallback. Tests cover defaults and precedence.
Configured session ID callers
container.go, generic.go, network.go, testcontainers.go, reaper_test.go
Container, network, generic label, public session, and reaper test paths use config.Read().SessionID.
Docker and bootstrap integration
docker_client.go, docker.go, internal/core/client.go
Docker clients retain loaded configuration. Reaper setup uses the provider session ID. Client headers use bootstrap project-path resolution and the configured session ID.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Suggested reviewers: stevenh

Poem

Poem

🐰 Config stores the session key,
Bootstrap supplies it when values are absent.
Docker and reaper read the same ID,
Tests verify each setting path,
One session keeps the trail aligned.

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The changes enable reaper reuse through a configurable session ID but do not implement the requested rolling cleanup window or reuse timeout. Implement the rolling cleanup window or document and demonstrate how the new session ID configuration fully satisfies the inactivity-based cleanup requirements.
Docstring Coverage ⚠️ Warning Docstring coverage is 55.56% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the main change: making the session ID configurable.
Description check ✅ Passed The description explains the configurable session ID and its purpose for long-running reusable containers.
Out of Scope Changes check ✅ Passed The changes remain focused on session ID configuration and reaper reuse, which are related to the linked issue.
✨ 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: 0

🧹 Nitpick comments (2)
testcontainers.go (1)

32-55: Update SessionID doc comment to match config‑based implementation

SessionID() now delegates to config.Read().SessionID, so the detailed description of how the ID is derived (parent PID + creation time, hashing, etc.) is no longer local to this function and may be overridden via config/env. Consider rewording the comment to describe it as “the current configured session ID” and, if needed, point to the bootstrap/config docs for the generation details.

docker.go (1)

924-932: Reaper now uses provider‑level SessionID; consider container ID if you ever support per‑container sessions

Using c.provider.config.SessionID when calling spawner.reaper aligns reaper lifetime with the configured, process‑wide session ID and matches the new config‑centric model. If, in the future, you want to honor per‑container LabelSessionID overrides consistently, this call would likely need to switch to c.sessionID instead; for the current design, though, the change is coherent.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 00f2020 and 01dc605.

📒 Files selected for processing (11)
  • container.go (2 hunks)
  • docker.go (1 hunks)
  • docker_client.go (3 hunks)
  • generic.go (2 hunks)
  • internal/config/config.go (3 hunks)
  • internal/config/config_test.go (36 hunks)
  • internal/core/bootstrap/bootstrap.go (1 hunks)
  • internal/core/client.go (2 hunks)
  • network.go (2 hunks)
  • reaper_test.go (1 hunks)
  • testcontainers.go (2 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-09-29T15:08:18.694Z
Learnt from: mdelapenya
Repo: testcontainers/testcontainers-go PR: 3320
File: modules/artemis/artemis.go:98-103
Timestamp: 2025-09-29T15:08:18.694Z
Learning: In testcontainers-go, nat.Port is a type alias for string, so untyped string constants can be passed directly to functions expecting nat.Port (like wait.ForListeningPort) without explicit type conversion - the Go compiler handles the implicit conversion automatically.

Applied to files:

  • network.go
🧬 Code graph analysis (10)
container.go (3)
internal/config/config.go (1)
  • Read (103-109)
internal/core/bootstrap/bootstrap.go (1)
  • SessionID (104-106)
testcontainers.go (1)
  • SessionID (53-55)
internal/core/client.go (2)
internal/core/bootstrap/bootstrap.go (2)
  • ProjectPath (100-102)
  • SessionID (104-106)
testcontainers.go (1)
  • SessionID (53-55)
internal/config/config.go (2)
internal/core/bootstrap/bootstrap.go (1)
  • SessionID (104-106)
testcontainers.go (1)
  • SessionID (53-55)
reaper_test.go (3)
internal/config/config.go (1)
  • Read (103-109)
internal/core/bootstrap/bootstrap.go (1)
  • SessionID (104-106)
testcontainers.go (1)
  • SessionID (53-55)
network.go (3)
internal/config/config.go (1)
  • Read (103-109)
internal/core/bootstrap/bootstrap.go (1)
  • SessionID (104-106)
testcontainers.go (1)
  • SessionID (53-55)
internal/config/config_test.go (2)
internal/core/bootstrap/bootstrap.go (1)
  • SessionID (104-106)
internal/config/config.go (1)
  • Config (34-97)
docker.go (3)
internal/core/docker_host.go (1)
  • DockerHostContextKey (19-19)
internal/core/bootstrap/bootstrap.go (1)
  • SessionID (104-106)
testcontainers.go (1)
  • SessionID (53-55)
generic.go (4)
internal/core/labels.go (1)
  • DefaultLabels (38-51)
internal/config/config.go (1)
  • Read (103-109)
internal/core/bootstrap/bootstrap.go (1)
  • SessionID (104-106)
testcontainers.go (1)
  • SessionID (53-55)
docker_client.go (2)
internal/config/config.go (2)
  • Config (34-97)
  • Read (103-109)
internal/core/bootstrap/bootstrap.go (2)
  • SessionID (104-106)
  • ProcessID (96-98)
testcontainers.go (2)
internal/config/config.go (1)
  • Read (103-109)
internal/core/bootstrap/bootstrap.go (1)
  • SessionID (104-106)
🔇 Additional comments (9)
internal/core/bootstrap/bootstrap.go (1)

1-105: Package rename to bootstrap looks safe

Exports and init semantics are unchanged; renaming the package to bootstrap aligns with the new import sites and keeps behavior intact.

internal/core/client.go (1)

11-38: HTTP headers now correctly use config‑driven session ID

Using bootstrap.ProjectPath() and tcConfig.SessionID wires the Docker client headers into the same bootstrap/config session machinery used elsewhere; this is consistent and non‑breaking.

reaper_test.go (1)

115-124: Session ID lookup in test aligned with config

Fetching the session via config.Read().SessionID keeps this test in sync with how the provider/reaper obtain the session ID after the refactor; the lookup logic remains correct.

container.go (1)

25-28: Container session ID now correctly derives from config

ContainerRequest.sessionID() still respects an explicit LabelSessionID but now falls back to config.Read().SessionID, which is exactly what you want for a configurable, process‑wide session ID.

Also applies to: 174-181

network.go (1)

55-61: Network session ID consistent with config‑driven model

Aligning NetworkRequest.sessionID() with config.Read().SessionID (while still honoring a LabelSessionID override) keeps networks and containers on the same configurable session semantics.

generic.go (1)

108-114: Generic labels now reflect configured session ID

Passing config.Read().SessionID into core.DefaultLabels ensures all auto‑applied labels (including the session label) follow the same configurable session ID used elsewhere.

docker_client.go (1)

15-18: SessionID wiring via config.Config in DockerClient looks consistent

The new config field, use of config.Read() in NewDockerClientWithOpts, and logging of c.config.SessionID in Info() are all consistent with the new config‑driven session semantics. Using bootstrap.ProcessID() here also aligns with the bootstrap accessor pattern. No functional issues spotted in this hunk.

Also applies to: 26-27, 81-91, 121-130

internal/config/config.go (1)

13-14: SessionID config field and env/props precedence are correctly implemented

The new SessionID field, its properties tag (session.id) and the precedence logic in applyEnvironmentConfiguration (env → properties → bootstrap.SessionID() fallback) are coherent and match the documented TESTCONTAINERS_SESSION_ID behavior. This gives a stable, overridable session ID without altering existing config semantics.

Also applies to: 57-63, 119-138

internal/config/config_test.go (1)

12-13: Tests thoroughly cover new SessionID behavior across env, properties, and defaults

The additions to resetTestEnv, the updated expectations using bootstrap.SessionID(), and the new table entries for session.id and TESTCONTAINERS_SESSION_ID correctly encode the intended precedence and defaulting rules. This should give good regression coverage for the new SessionID configuration path.

Also applies to: 24-32, 47-59, 71-78, 85-102, 112-115, 126-132, 140-157, 163-167, 179-181, 220-224, 232-236, 243-247, 263-268, 275-279, 286-291, 298-301, 311-314, 325-328, 335-339, 348-352, 361-365, 374-378, 387-391, 416-420, 429-433, 458-462, 471-475, 502-505, 528-532, 541-545, 554-558, 561-582

mdelapenya
mdelapenya previously approved these changes Jan 29, 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! I'm approving it even though I added a comment that would be good to add.

Once addressed, I think we can re-run the CI and merge.

Thanks!

PS: Many times, we are forced to do multitasking, so please sorry for taking too long to address this.

Comment thread internal/config/config.go
@jcmfernandes

Copy link
Copy Markdown
Contributor Author

LGTM! I'm approving it even though I added a comment that would be good to add.

Once addressed, I think we can re-run the CI and merge.

Thanks!

PS: Many times, we are forced to do multitasking, so please sorry for taking too long to address this.

Nothing to apologize for! Thanks, everyone, for the thorough review. 🙌

@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

🤖 Fix all issues with AI agents
In `@internal/config/config.go`:
- Around line 133-138: Current logic always overwrites config.SessionID with
bootstrap.SessionID() when the TESTCONTAINERS_SESSION_ID env var is unset,
ignoring any value already loaded from the properties file; change the logic in
the block handling TESTCONTAINERS_SESSION_ID/sessionID so that: if the env var
is set, assign it to config.SessionID; else if config.SessionID is already
non-empty (loaded from properties) leave it untouched; otherwise set
config.SessionID = bootstrap.SessionID(). Update the code that references
sessionID, config.SessionID and bootstrap.SessionID() accordingly to implement
this three-way precedence (env -> properties -> bootstrap).

Comment thread internal/config/config.go
@mdelapenya

Copy link
Copy Markdown
Member

Some tests are failing on CI, can you check?

@jcmfernandes

jcmfernandes commented Jan 30, 2026

Copy link
Copy Markdown
Contributor Author

Some tests are failing on CI, can you check?

After all, that "else if" statement is necessary, as the AI bot correctly pointed out. I deleted the commit.

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
docker.go (4)

845-859: 🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

Keep log-production state per run.

startLogProduction overwrites shared fields logProductionCtx, c.logProductionCancel, c.logProductionDone, and c.logProductionTimeout while an existing c.logProducer might still read them. stopLogProduction cancels and waits only on the latest run, so an earlier run can continue. Store each run in a synchronized immutable run object and pass that run’s context and timeout into c.logProducer. Cancel and wait for the active run before replacing it. Add a race-enabled test that starts and stops log production concurrently.

🤖 Prompt for 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.

In `@docker.go` around lines 845 - 859, The startLogProduction flow must keep
context, cancel, completion, and timeout state scoped to an immutable per-run
object instead of overwriting shared fields while a producer is active. Update
startLogProduction and stopLogProduction to synchronize access, cancel and await
the current run before replacing it, and pass that run’s context and timeout
directly into c.logProducer; add a race-enabled test covering concurrent start
and stop operations.

596-612: 🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

Bound buffered Exec output.

DockerContainer.Exec buffers the entire attach stream in bytes.Buffer before returning. A command that keeps producing stdout/stderr can exhaust process memory before the caller reads the result. Add a configurable output limit and return a defined error when the limit is exceeded; verify this with an exec command that emits more than the configured limit.

🤖 Prompt for 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.

In `@docker.go` around lines 596 - 612, Update DockerContainer.Exec’s
attach-stream handling around the io.Copy goroutine to write through a bounded
reader or limited buffer, using a configurable maximum output size. Detect when
the limit is exceeded, return a defined limit-exceeded error instead of
continuing to buffer, preserve context-cancellation behavior, and add coverage
with an exec command that emits more than the configured limit.

1383-1393: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Escape the literal container name in the Docker name filter.

findContainerByName anchors name in a regex, so cache.1 also matches cacheX1 via the dot wildcard. ReuseOrCreateContainer can then return that wrong container. Append regexp.QuoteMeta to the filter value.

Proposed fix
-		Filters: make(client.Filters).Add("name", fmt.Sprintf("^%s$", name)),
+		Filters: make(client.Filters).Add("name", fmt.Sprintf("^%s$", regexp.QuoteMeta(name))),

Add a reuse test with two confusable names and assert that only the literal name is reused.

🤖 Prompt for 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.

In `@docker.go` around lines 1383 - 1393, Update findContainerByName’s Docker name
filter to escape the literal name with regexp.QuoteMeta before applying the
existing anchors, preventing regex metacharacters from matching confusable
container names. Add a reuse test covering two names that differ only by a regex
metacharacter and verify ReuseOrCreateContainer reuses only the exact literal
name.

222-224: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Handle HostPort parsing failures in MappedPort.

MappedPort discards errors from parsing p[0].HostPort and constructing the returned network.Port, so invalid or out-of-range bindings can be reported as a successful mapping or a zero/overflown port. Return and wrap the parse/construct errors instead.

🤖 Prompt for 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.

In `@docker.go` around lines 222 - 224, Update MappedPort’s HostPort handling to
check and return errors from strconv.ParseUint and network.PortFrom instead of
discarding them. Wrap each error with contextual information while preserving
the successful mapped-port return path.

Source: Linters/SAST tools

🤖 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.

Outside diff comments:
In `@docker.go`:
- Around line 845-859: The startLogProduction flow must keep context, cancel,
completion, and timeout state scoped to an immutable per-run object instead of
overwriting shared fields while a producer is active. Update startLogProduction
and stopLogProduction to synchronize access, cancel and await the current run
before replacing it, and pass that run’s context and timeout directly into
c.logProducer; add a race-enabled test covering concurrent start and stop
operations.
- Around line 596-612: Update DockerContainer.Exec’s attach-stream handling
around the io.Copy goroutine to write through a bounded reader or limited
buffer, using a configurable maximum output size. Detect when the limit is
exceeded, return a defined limit-exceeded error instead of continuing to buffer,
preserve context-cancellation behavior, and add coverage with an exec command
that emits more than the configured limit.
- Around line 1383-1393: Update findContainerByName’s Docker name filter to
escape the literal name with regexp.QuoteMeta before applying the existing
anchors, preventing regex metacharacters from matching confusable container
names. Add a reuse test covering two names that differ only by a regex
metacharacter and verify ReuseOrCreateContainer reuses only the exact literal
name.
- Around line 222-224: Update MappedPort’s HostPort handling to check and return
errors from strconv.ParseUint and network.PortFrom instead of discarding them.
Wrap each error with contextual information while preserving the successful
mapped-port return path.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 87fedd03-7ccd-4ab4-80a2-d46657e65d3f

📥 Commits

Reviewing files that changed from the base of the PR and between 1fb204d and f2c1769.

📒 Files selected for processing (8)
  • container.go
  • docker.go
  • docker_client.go
  • generic.go
  • internal/config/config.go
  • internal/config/config_test.go
  • internal/core/bootstrap/bootstrap.go
  • internal/core/client.go
🚧 Files skipped from review as they are similar to previous changes (5)
  • internal/core/bootstrap/bootstrap.go
  • container.go
  • internal/core/client.go
  • generic.go
  • docker_client.go

@jcmfernandes

Copy link
Copy Markdown
Contributor Author

@mdelapenya mind giving this a final look? Thank you so much.

@mdelapenya

mdelapenya commented Aug 5, 2026

Copy link
Copy Markdown
Member

@jcmfernandes can you rebase from current main 🙏 Fine if you push-force, as the changeset's size is reduced

BTW I'm cutting a new release soon, and this work will land into it (sorry for the late review 😞 )

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@jcmfernandes

Copy link
Copy Markdown
Contributor Author

Rebased @mdelapenya, thank you! 🙌

I opened #3837 as it was raised the LLM code review added to this branch and it's a genuine bug.

@mdelapenya

Copy link
Copy Markdown
Member

@jcmfernandes for some reason I cannot update your PR branches. Could you update them yourself? I already fixed the lint error for the azurite module

@jcmfernandes

Copy link
Copy Markdown
Contributor Author

@jcmfernandes for some reason I cannot update your PR branches. Could you update them yourself? I already fixed the lint error for the azurite module

Rebased on main.

@mdelapenya

Copy link
Copy Markdown
Member

CI fails, could you take a look?

@jcmfernandes

Copy link
Copy Markdown
Contributor Author

CI fails, could you take a look?

Done. It was something wonky that stem from the review but truly is necessary.

Comment thread internal/config/config.go

@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 6fdd2fd into testcontainers:main Aug 7, 2026
560 of 561 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature New functionality or new behaviors on the existing one

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: Support a reuseWindow for cleaning up reusable containers if no tests run within a certain duration

4 participants