Modules/businessdev.ALbuild.Containers/Public/Wait-BcContainerReady.ps1
|
function Wait-BcContainerReady { <# .SYNOPSIS Waits for a Business Central container to report that it is ready for connections. .DESCRIPTION Polls the container log for the ready marker emitted by the generic image, failing fast if the container exits before becoming ready or if the timeout elapses. While waiting it streams the container's new start-script log lines to the console (and a periodic heartbeat when the log is quiet) so a long initialisation never looks hung. .PARAMETER Name Container name. .PARAMETER TimeoutSeconds Maximum time to wait. Default 1200 (20 minutes). .PARAMETER ReadyText The log text that signals readiness. Default 'Ready for connections'. .PARAMETER PollIntervalSeconds Seconds between polls. Default 5. .PARAMETER HeartbeatSeconds Emit an "elapsed" heartbeat after this many seconds without new log output. Default 30. .PARAMETER NoProgress Suppress streaming the container's startup log lines (the readiness check and heartbeat still apply). .PARAMETER DockerExecutable The Docker executable to use (default 'docker'). .OUTPUTS System.Boolean ($true when ready; otherwise throws). #> [CmdletBinding()] [OutputType([bool])] param( [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string] $Name, [ValidateRange(1, [int]::MaxValue)] [int] $TimeoutSeconds = 1200, [string] $ReadyText = 'Ready for connections', [ValidateRange(1, 3600)] [int] $PollIntervalSeconds = 5, [ValidateRange(1, [int]::MaxValue)] [int] $HeartbeatSeconds = 30, [switch] $NoProgress, [string] $DockerExecutable = 'docker' ) $start = Get-Date $deadline = $start.AddSeconds($TimeoutSeconds) $escaped = [regex]::Escape($ReadyText) $printedLines = 0 $lastOutput = $start while ((Get-Date) -lt $deadline) { $logs = Invoke-BcDocker -DockerExecutable $DockerExecutable -Quiet -PassThru -Arguments @('logs', $Name) $stdOut = "$($logs.StdOut)" # Stream the start-script log lines that appeared since the last poll, so progress is visible. if ($logs.Success -and -not $NoProgress) { $lines = @($stdOut -split "`r?`n") for ($i = $printedLines; $i -lt $lines.Count; $i++) { if (-not [string]::IsNullOrWhiteSpace($lines[$i])) { Write-Host " [$Name] $($lines[$i].TrimEnd())" $lastOutput = Get-Date } } $printedLines = $lines.Count } if ($logs.Success -and (("$stdOut`n$($logs.StdErr)") -match $escaped)) { Write-ALbuildLog -Level Success "Container '$Name' is ready ($([int]((Get-Date) - $start).TotalSeconds)s)." return $true } $container = Get-BcContainer -Name $Name -DockerExecutable $DockerExecutable if ($container -and -not $container.Running) { throw "Container '$Name' exited before becoming ready (status: $($container.Status)).$(Get-BcContainerLogTail -Name $Name -DockerExecutable $DockerExecutable)" } # Heartbeat when the log has been quiet, so the wait never looks frozen. if (((Get-Date) - $lastOutput).TotalSeconds -ge $HeartbeatSeconds) { Write-ALbuildLog -Level Information "Still waiting for container '$Name' to become ready... ($([int]((Get-Date) - $start).TotalSeconds)s elapsed)" $lastOutput = Get-Date } Start-Sleep -Seconds $PollIntervalSeconds } throw "Timed out after $TimeoutSeconds s waiting for container '$Name' to become ready.$(Get-BcContainerLogTail -Name $Name -DockerExecutable $DockerExecutable)" } |