Skip to content

Bound the site-readiness poll in ship and survive connection failures - #216

Merged
joetannenbaum merged 4 commits into
laravel:mainfrom
usamamuneerchaudhary:main
Sep 4, 2026
Merged

Bound the site-readiness poll in ship and survive connection failures#216
joetannenbaum merged 4 commits into
laravel:mainfrom
usamamuneerchaudhary:main

Conversation

@usamamuneerchaudhary

Copy link
Copy Markdown
Contributor

Problem

After a successful deploy, cloud ship asks whether to open the site and then polls the environment URL in Ship::waitForUrlToBeReady():

do {
    $response = Http::get($environment->url);
    Sleep::for(CarbonInterval::seconds(2));
} while (! $response->successful() && ! $response->serverError());

This has three problems:

  • It can loop forever. The only exits are a 2xx or a 5xx. Any persistent 4xx, a 404 while the vanity domain is still propagating, a 403 from a maintenance page, a 401 on an API-only app, leaves the "Waiting for site to be ready..." spinner running until the user hits Ctrl+C.
  • A connection failure crashes the command. Http::get() throws ConnectionException on a DNS failure or refused connection. Nothing catches it, so the user gets a stack trace immediately after a deploy that actually succeeded.
  • No per-request timeout, so a hanging connection also blocks the loop indefinitely.

This is the same class of bug as #193 (a validation loop with no exit), on the HTTP side.

Change

waitForUrlToBeReady() now uses Laravel's retry() helper with an attempt budget:

  • Polls at most $maxAttempts times (default 60, i.e. ~2 minutes at the existing 2-second interval), then returns false so the caller falls through to the existing "It looks like there is an error in your deployed site" path, which already offers to open the logs.
  • A 4xx is turned into a RequestException via throwIf($response->clientError()) and retried; a ConnectionException is retried the same way. Both mean "not ready yet."
  • A 2xx returns true and a 5xx returns false on the first response, exactly as before.
  • Uses Http::timeout(10) per request.

The signature is backward-compatible ($maxAttempts has a default) and the only call site is the spin() in Ship::handle(), so no caller changes.

@joetannenbaum

Copy link
Copy Markdown
Collaborator

Thank you!

@joetannenbaum
joetannenbaum merged commit f8e8132 into laravel:main Sep 4, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants