func WaitPort()

in internal/components/setup/compose_provider.go [459:516]


func WaitPort(ctx context.Context, target wait.StrategyTarget, waitPort nat.Port, timeout time.Duration) (err error) {
	// limit context to startupTimeout
	ctx, cancelContext := context.WithTimeout(ctx, timeout)
	defer cancelContext()

	ipAddress, err := target.Host(ctx)
	if err != nil {
		return
	}

	var waitInterval = 100 * time.Millisecond

	port, err := findMappedPort(ctx, target, waitPort)

	proto := port.Proto()
	portNumber := port.Int()
	portString := strconv.Itoa(portNumber)

	// external check
	dialer := net.Dialer{}
	address := net.JoinHostPort(ipAddress, portString)
	for {
		conn, err := dialer.DialContext(ctx, proto, address)
		if err != nil {
			if v, ok := err.(*net.OpError); ok {
				if v2, ok := (v.Err).(*os.SyscallError); ok {
					if isConnRefusedErr(v2.Err) {
						time.Sleep(waitInterval)
						continue
					}
				}
			}
			return err
		}
		conn.Close()
		break
	}

	// internal check
	command := buildInternalCheckCommand(waitPort.Int())
	for {
		if ctx.Err() != nil {
			return ctx.Err()
		}
		exitCode, err := target.Exec(ctx, []string{"/bin/sh", "-c", command})
		if err != nil {
			return err
		}

		if exitCode == 0 {
			break
		} else if exitCode == 126 {
			return errors.New("/bin/sh command not executable")
		}
	}

	return nil
}