testcontainers / moby-ryuk

Schedule Moby/Docker containers cleanup after specific delay.
https://www.testcontainers.com
MIT License
182 stars 33 forks source link

Would love Reuse with Ryuk 🤝🥰 #157

Open PureKrome opened 2 weeks ago

PureKrome commented 2 weeks ago

TestContainers accepts the experimental option of "Reuse" to help save you (startup) time.

An example of this is on each one of our developer machines, where we're constantly running tests and tap-tap-tapping away at code. Great!

Reuse option means the moby-ryuk reaper doesn't start. The instance(s) now never get destroyed.

But can we have our cake an eat it?

Would be really nice if there could be an option to have it tear down after 'x' seconds or minutes of no test calls. That last bit (emphasized by me) is the kicker.

MAGIC SAUCE

Every time a test is ran (which leverages their custom TestFixture), we can 'remember' that the test is using the container. The Reaper just sits there waiting to see if they haven't used the container for whatever time setting they asked.

The TestContainer SDK offers a new method which will allow us to tell the moby-ryuk instance that we're running a test now.

E.g.

Developer is using TestContainers with a Database (anything) running. Following the .NET documentation, I'll create the following class (stripped down/back, to reduce noise in this issue)

public class MyAwesomeFancyPantsDatabaseFixture : IAsyncLifetime
{
    ...

    public async Task InitializeAsync()
    {
        await _reaper.PingAsync(); // <-- THIS
    }

    ...
}

If I was using xUnit, then my test class will run this once per xunit COLLECTION. Which is ok. Would be nicer if it was per test. I guess I could expose that in the ctor of the test class like:

[Collection("MyAwesomeFancyPantsDatabase TestContainers Collection")]
public class EndpointTests : IClassFixture<MyAwesomeFancyPantsDatabaseFixture >, IAsyncLifetime
{
    public async Task InitializeAsync()
    {
        await _myAwesomeFancyPantsDatabaseFixture.PingAsync(); // Or whatever...
    };

    ....
}

So we don't get instant tear down .. but if the container hasn't been used after x seconds, minutes, whatever, then the Reaper does it stuff and tears the container down and then finally, itself.

EDIT: Forget to describe the setup..

Oh! and we can setup this magical setting like ..

public SqlServerFixture() =>
    _msSqlContainer = new MsSqlBuilder()
        .WithImage("fancypants:latest")
        .WithExposedPort(10000)
        .WithReuse(true, TimeSpan.FromMinutes(20)) // <-- 🪄 🌠 PEW PEW! MAGIC HAPPENS HERE
        .Build();

Thoughts?