C# + DockerCompose - дождитесь, пока контейнер Docker MS SQL Server будет запущен, прежде чем пытаться подключиться
Я пытаюсь создать интеграционные тесты для моих микросервисов, аналогичные подходу Spotify.
Я все еще работаю над тем, как раскрутить базу данных. В настоящее время у меня есть проект.NET Core 2.0 с FluentDocker v2.2.15 и DbUp 4.1.0.
Я использую FluentDocker для вызова DockerCompose и запуска своих служб, включая контейнер SQL Server.
var hosts = new Hosts().Discover();
var dockerHost = hosts.FirstOrDefault(x => x.IsNative) ?? hosts.FirstOrDefault(x => x.Name == "default");
if (dockerHost == null)
{
return;
}
var composeFile = Args["composeFile"];
var result = dockerHost.Host.ComposeUp(composeFile: composeFile);
а затем я использую DbUp для запуска своих скриптов и заполнения базы данных.
var connectionString = Args["connectionString"];
var scriptsPath = Args["scriptsPath"];
EnsureDatabase.For.SqlDatabase(connectionString);
var upgradeEngine = DeployChanges.To.SqlDatabase(connectionString).WithScriptsFromFileSystem(scriptsPath).Build();
var result = upgradeEngine.PerformUpgrade();
Я могу запустить это успешно, когда я даю SQL Server достаточно времени для запуска, например, при отладке. Однако, если я запускаю это на полной скорости, тогда DbUp пытается подключиться к SQL Server, когда он еще не готов.
FluentDocker имеет WaitForPort
метод, но он, похоже, не работает с DockerCompose API.
Я хотел бы знать, есть ли способ подождать, пока порт SQL Server 1433 будет реагировать, прежде чем запускать сценарии (исключая недетерминированные тактики, такие как await Task.Delay
) или если есть альтернативные библиотеки, которые позволяют мне иметь такой контроль.
Спасибо
1 ответ
Ты можешь использовать WaitForPort
, WaitForProcess
, WaitForHttp
или пользовательская лямбда Wait
функции по созданию в FluentDocker v2.6.2. Например:
Имеется файл docker-compose:
version: '3.3'
services:
db:
image: mysql:5.7
volumes:
- db_data:/var/lib/mysql
restart: always
environment:
MYSQL_ROOT_PASSWORD: somewordpress
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: wordpress
wordpress:
depends_on:
- db
image: wordpress:latest
ports:
- "8000:80"
restart: always
environment:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: wordpress
volumes:
db_data:
Файл указывает, что WordPress зависит от БД, и, таким образом, сначала запускается БД, а затем создается экземпляр WordPress. Однако для обеспечения того, чтобы в рамках using
пункт, что WordPress Web работает, вам нужно использовать HTTP, чтобы определить именно это. Вы можете использовать Fluent API для создания экземпляра и ожидания запуска службы следующим образом.
var file = Path.Combine(Directory.GetCurrentDirectory(),
(TemplateString) "Resources/ComposeTests/WordPress/docker-compose.yml");
using (new Builder()
.UseContainer()
.UseCompose()
.FromFile(file)
.RemoveOrphans()
.Wait("wordpress", (service, cnt) => {
if (cnt > 60) throw new FluentDockerException("Failed to wait for wordpress service");
var res = HttpExtensions.DoRequest("http://localhost:8000/wp-admin/install.php").Result;
return (res.Code == HttpStatusCode.OK &&
res.Body.IndexOf("https://wordpress.org/", StringComparison.Ordinal) != -1) ? 0 : 500;
})
.Build().Start())
{
// Since we have waited - this shall now always work.
var installPage = await "http://localhost:8000/wp-admin/install.php".Wget();
Assert.IsTrue(installPage.IndexOf("https://wordpress.org/", StringComparison.Ordinal) != -1);
}
(Приведенный выше пример является более громоздким WaitForHttp
но используя собственную лямбду, чтобы проиллюстрировать смысл).
Таким образом, вы можете даже использовать соединение БД и запросить таблицу перед продолжением. Возвращаемые значения выше нуля - это время ожидания следующего теста. Ноль и ниже успешно завершат ожидание. Исключение прервет ожидание (и потерпит неудачу).
В приведенном выше примере используется синтаксис FluentAPI, но вы можете вручную добавить хук к контейнеру компоновки и использовать расширения самостоятельно.
Ура, Марио