wait

package
v1.6.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 19, 2026 License: Apache-2.0 Imports: 14 Imported by: 0

Documentation

Overview

Package wait provides composable readiness wait-strategies for Docker containers. It generalizes the library's log-line readiness model into reusable predicates (HTTP probes, in-container commands, raw TCP connects, log matching) combined with ForAll / ForAny / ForAtLeast.

A Strategy is a pure function predicate with strict (bool, error) semantics:

(true, nil)  = ready now
(false, nil) = not ready yet (retry)
(_, err)     = fatal — stop immediately

Wait owns the single shared poll loop; strategies never loop on their own. Timeouts and intervals are global to a Wait call, not per-strategy.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Wait

func Wait(ctx context.Context, t Target, s Strategy, opts ...Option) error

Wait runs a single strategy against t via the shared poller, honouring the ctx deadline. It returns nil as soon as the strategy reports ready, or a wrapped error on a fatal strategy error or on the deadline/timeout elapsing.

Example

ExampleWait demonstrates the top-level Wait function: polling a target until a readiness strategy reports ready. Wait is the entry point for every strategy and combinator in this package.

err := Wait(context.Background(), &fakeTarget{}, ForCommand([]string{"echo", "ok"}))
if err != nil {
	fmt.Printf("error: %v\n", err)
	return
}

fmt.Println("ready")
Output:
ready

Types

type Option

type Option func(*config)

Option configures a Wait call or a strategy constructor. Options that do not apply to a particular consumer are ignored (see DESIGN §2.4).

func WithBodyContains

func WithBodyContains(substr string) Option

WithBodyContains requires the response body to contain substr for the probe to be ready. Default "" (no body check).

func WithExitCode

func WithExitCode(code int) Option

WithExitCode sets the expected exit code. Default 0.

func WithInterval

func WithInterval(d time.Duration) Option

WithInterval sets the poll interval. Non-positive values are clamped to the default (200ms). Default: 200ms.

func WithMethod

func WithMethod(m string) Option

WithMethod sets the HTTP method. Default GET.

func WithPath

func WithPath(p string) Option

WithPath sets the request path. Default "/".

func WithResponseStatuses

func WithResponseStatuses(codes ...int) Option

WithResponseStatuses overrides the accepted status set (default: any 2xx).

func WithTLS

func WithTLS(b bool) Option

WithTLS selects the https scheme. When true the per-request client trusts a self-signed certificate (InsecureSkipVerify) so the strategy can probe test TLS servers. Default false (http).

func WithTimeout

func WithTimeout(d time.Duration) Option

WithTimeout bounds the whole Wait call when ctx carries no deadline. An explicit ctx deadline is authoritative and overrides this. Non-positive values are clamped to the default (60s). Default: 60s.

type Strategy

type Strategy = func(ctx context.Context, t Target) (bool, error)

Strategy is a readiness predicate. See the (bool, error) semantics table in the package documentation. It is a type alias (not a named type) so that one-line inline strategies are assignable while named strategies may still carry a String() method for diagnostics.

func ForAll

func ForAll(strategies ...Strategy) Strategy

ForAll returns a strategy that is ready when all sub-strategies are ready. An empty list is vacuously ready immediately.

Example

ExampleForAll demonstrates combining strategies: ForAll reports ready only when every sub-strategy is ready. Here a command probe and a TCP liveness probe must both succeed.

err := Wait(
	context.Background(),
	&fakeTarget{},
	ForAll(
		ForCommand([]string{"echo", "ok"}),
		ForCommand([]string{"true"}),
	),
)
if err != nil {
	fmt.Printf("error: %v\n", err)
	return
}

fmt.Println("ready")
Output:
ready

func ForAny

func ForAny(strategies ...Strategy) Strategy

ForAny returns a strategy that is ready when at least one sub-strategy is ready. An empty list is never satisfiable and always times out.

Example

ExampleForAny demonstrates combining strategies: ForAny reports ready as soon as at least one sub-strategy is ready.

err := Wait(
	context.Background(),
	&fakeTarget{},
	ForAny(
		ForCommand([]string{"false", "ignored"}),
		ForCommand([]string{"echo", "ok"}),
	),
)
if err != nil {
	fmt.Printf("error: %v\n", err)
	return
}

fmt.Println("ready")
Output:
ready

func ForAtLeast

func ForAtLeast(x int, strategies ...Strategy) Strategy

ForAtLeast returns a strategy that is ready when at least x of the sub-strategies are ready. Sub-strategies run concurrently for each poll via errgroup. Edge cases: x <= 0 is vacuous success; x > len(strategies) can never be satisfied (the poller times out).

Example

ExampleForAtLeast demonstrates combining strategies: ForAtLeast(x, ...) is ready when at least x of the sub-strategies are ready.

err := Wait(
	context.Background(),
	&fakeTarget{},
	ForAtLeast(1,
		ForCommand([]string{"echo", "ok"}),
		ForCommand([]string{"echo", "also ok"}),
	),
)
if err != nil {
	fmt.Printf("error: %v\n", err)
	return
}

fmt.Println("ready")
Output:
ready

func ForCommand

func ForCommand(cmd []string, opts ...Option) Strategy

ForCommand returns a strategy that is ready when running cmd inside the container exits with the expected code (default 0 via WithExitCode).

The root package's Exec reports a non-zero exit code in the result, not as an error; only an infrastructure failure (create/attach/IO) is returned as an error and treated as fatal.

Example

ExampleForCommand demonstrates probing a container by running a command inside it. ForCommand reports ready as soon as the command exits with code 0.

err := Wait(context.Background(), &fakeTarget{}, ForCommand([]string{"echo", "ok"}))
if err != nil {
	fmt.Printf("error: %v\n", err)
	return
}

fmt.Println("ready")
Output:
ready

func ForHTTPGet

func ForHTTPGet(port uint16, opts ...Option) Strategy

ForHTTPGet returns a strategy that is ready when an HTTP request to the container's internal port returns an accepted status (default 2xx, overridable via WithResponseStatuses) and, if WithBodyContains is set, a body containing the substring.

"connection refused" (server not listening yet) and unaccepted statuses are transient retries. An invalid URL or a TLS handshake failure is fatal, as is t.URL reporting the port as not registered.

Example

ExampleForHTTPGet demonstrates probing a container by making an HTTP request to one of its ports. ForHTTPGet reports ready once the probe returns an accepted status on the requested path.

srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
	w.WriteHeader(http.StatusOK)
}))
defer srv.Close()

host, portStr, err := net.SplitHostPort(srv.Listener.Addr().String())
if err != nil {
	fmt.Printf("error: %v\n", err)
	return
}
port, err := strconv.Atoi(portStr)
if err != nil || port < 0 || port > int(^uint16(0)) {
	fmt.Printf("error: invalid port %q\n", portStr)
	return
}

t := &fakeTarget{hostPort: &docker.HostPort{Host: host, Port: uint16(port)}}

err = Wait(
	context.Background(),
	t,
	ForHTTPGet(uint16(port), WithPath("/health"), WithResponseStatuses(http.StatusOK)),
)
if err != nil {
	fmt.Printf("error: %v\n", err)
	return
}

fmt.Println("ready")
Output:
ready

func ForLog

func ForLog(m docker.Matcher, opts ...Option) Strategy

ForLog returns a strategy that is ready when some line of container output matches m. The Target must implement the optional GetOutput capability; otherwise ForLog returns a fatal error.

Example

ExampleForLog demonstrates matching a line of container output. ForLog is ready once some line matches the given matcher. It requires a Target that implements the optional GetOutput capability (docker.Container and docker.TestContainer both do).

t := &logFakeTarget{
	fakeTarget: &fakeTarget{},
	lines:      []string{"started", "READY"},
}

err := Wait(
	context.Background(),
	t,
	ForLog(docker.NewSubstringMatcher("READY")),
)
if err != nil {
	fmt.Printf("error: %v\n", err)
	return
}

fmt.Println("ready")
Output:
ready

func ForTCPConnection

func ForTCPConnection(port uint16, opts ...Option) Strategy

ForTCPConnection returns a strategy that is ready when a TCP connection to the container's internal port can be established (and is immediately closed). This is a pure liveness probe: it proves the listener accepts connections but says nothing about application readiness.

A refused/unreachable connect is a transient retry; t.URL reporting the port as not registered is fatal. UDP is not supported: there is no acknowledgement on a UDP "connection", so a connect-style liveness probe is meaningless.

Example

ExampleForTCPConnection demonstrates a pure TCP liveness probe: ForTCPConnection reports ready once a TCP connection to the container's internal port can be established.

// A listener that accepts connections immediately, acting as the "service".
l, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
	fmt.Printf("error: %v\n", err)
	return
}
defer func() { _ = l.Close() }()

_, portStr, err := net.SplitHostPort(l.Addr().String())
if err != nil {
	fmt.Printf("error: %v\n", err)
	return
}
port, err := strconv.Atoi(portStr)
if err != nil || port < 0 || port > int(^uint16(0)) {
	fmt.Printf("error: invalid port %q\n", portStr)
	return
}

// ForTCPConnection dials the listener's own port via t.URL.
t := &fakeTarget{hostPort: &docker.HostPort{Host: "127.0.0.1", Port: uint16(port)}}

err = Wait(context.Background(), t, ForTCPConnection(uint16(port)))
if err != nil {
	fmt.Printf("error: %v\n", err)
	return
}

fmt.Println("ready")
Output:
ready

type Target

type Target interface {
	URL(proto docker.Protocol, port uint16) (*docker.HostPort, error)
	Exec(ctx context.Context, cmd []string) (*docker.ExecResult, error)
}

Target is the minimal capability a strategy needs from a container. Both docker.Container and docker.TestContainer satisfy it directly.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL