Since the reuse feature became available I started using Testcontainers to automate setting up a development database. I have created a hosted service that goes like this:
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Testcontainers.MsSql;
namespace SampleCode;
internal class DockerDatabaseService : IHostedService
{
private readonly IDbContextFactory<MyDbContext> _dbContextFactory;
private readonly MsSqlContainer _container;
public DockerDatabaseService(IHostEnvironment environment, IDbContextFactory<MyDbContext> dbContextFactory, ILoggerFactory loggerFactory)
{
if (!environment.IsDevelopment())
{
throw new NotSupportedException($"{nameof(DockerDatabaseService)} must only be used in the development environment but the current environment is \"{environment.EnvironmentName}\"");
}
_dbContextFactory = dbContextFactory;
_container = new MsSqlBuilder()
.WithLogger(loggerFactory.CreateLogger("Testcontainers"))
.WithReuse(true)
.WithName(environment.ApplicationName)
.WithPortBinding(hostPort: 1433, containerPort: 1433)
.Build();
}
public async Task StartAsync(CancellationToken cancellationToken)
{
await _container.StartAsync(cancellationToken);
await using var dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken);
await dbContext.Database.MigrateAsync(cancellationToken);
}
public async Task StopAsync(CancellationToken cancellationToken)
{
await _container.StopAsync(cancellationToken);
}
}
The Testcontainers.MsSql package is included conditionally for debug builds only:
And the hosted service is also registered conditionally for debug builds in the development environment:
#if DEBUG
if (environment.IsDevelopment())
{
services.AddHostedService<DockerDatabaseService>();
}
#endif
It worked so well that I used it in several projects. But then the same container was reused across different projects. Since I explicitly set a container name (WithName(environment.ApplicationName)) I assumed that the reuse mechanism would use it but it does not.
Solution
I think the container name (just like network and volume names) should be part of the reuse hash.
Benefit
Container reuse would work out of the box by just setting an explicit container name.
Alternatives
Currently I'm working around this issue by configuring the container with a reuse-id label:
_container = new MsSqlBuilder()
.WithLogger(loggerFactory.CreateLogger("Testcontainers"))
.WithReuse(true)
.WithLabel("reuse-id", environment.ApplicationName) // 👈 goes into the reuse hash
.WithName(environment.ApplicationName)
.WithPortBinding(hostPort: 1433, containerPort: 1433)
.Build();
Would you like to help contributing this enhancement?
Problem
Since the reuse feature became available I started using Testcontainers to automate setting up a development database. I have created a hosted service that goes like this:
The
Testcontainers.MsSql
package is included conditionally for debug builds only:And the hosted service is also registered conditionally for debug builds in the development environment:
It worked so well that I used it in several projects. But then the same container was reused across different projects. Since I explicitly set a container name (
WithName(environment.ApplicationName)
) I assumed that the reuse mechanism would use it but it does not.Solution
I think the container name (just like network and volume names) should be part of the reuse hash.
Benefit
Container reuse would work out of the box by just setting an explicit container name.
Alternatives
Currently I'm working around this issue by configuring the container with a
reuse-id
label:Would you like to help contributing this enhancement?
Yes: #1162