Skip to content

feat: user-defined readiness checks via readyOn#188

Open
mikenomitch wants to merge 8 commits intomainfrom
feat/readiness-checks
Open

feat: user-defined readiness checks via readyOn#188
mikenomitch wants to merge 8 commits intomainfrom
feat/readiness-checks

Conversation

@mikenomitch
Copy link
Copy Markdown
Collaborator

@mikenomitch mikenomitch commented Apr 21, 2026

Adds a way to define arbitrary readiness hooks that must resolve before fetch requests are proxied to the container.

Today, the de-facto readiness check is "are the declared ports listening?". That's baked into startAndWaitForPorts and there's no way to express "also wait for /health to return 200" or "wait for this warmup promise" without writing imperative code around containerFetch. This PR turns port-waiting into one of several composable checks.

Usage:

import { Container, portResponding, pathHealthy } from '@cloudflare/containers';

class MyApp extends Container {
  defaultPort = 8080;
  readyOn = [
    portResponding(8080),
    isHealthy('/health'),
    async () => { await myWarmup(); },
  ];
}

Main changes:

  • New ReadinessCheck type: (container, options?) => Promise<unknown>. Checks run in parallel via Promise.all; any rejection fails readiness.
  • New class-body attribute readyOn?: ReadinessCheck[]. When undefined, defaults are derived from defaultPort / requiredPorts — preserving today's behaviour.
  • New instance methods addReadinessCheck(check) and setReadinessChecks(checks). setReadinessChecks([]) opts out entirely.
  • New factories portResponding(port) and pathHealthy(path, port?).
  • New Container.waitForPath({ path, portToCheck, ... }) — polling analogue of waitForPort that requires 2xx.
  • startAndWaitForPorts internals now delegate to the readiness-check machinery. Explicit ports args still behave as before; no args runs readyOn (or the derived default).

Tests live in examples/core-tests — added a ReadyOnContainer whose /health endpoint returns 503 for the first 1.5s, and a test that verifies pathHealthy polls until healthy before the proxied fetch returns 200.

Notes:

  • Raw Promises in the list aren't supported; wrap as () => myPromise. Class-body initializers fire at construction, so eager promises would start before the container is known.
  • Docs updated in AGENTS.md; changeset added (minor bump).

@mikenomitch mikenomitch requested a review from a team as a code owner April 21, 2026 18:17
@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented Apr 21, 2026

Open in StackBlitz

npm i https://pkg.pr.new/cloudflare/containers/@cloudflare/containers@188

commit: 1e2992d

@mikenomitch
Copy link
Copy Markdown
Collaborator Author

Noting stuff for reviewers to look at:

  • naming
  • signature and behavior of the custom callbacks -> If they fail they cancel the fetch I believe, do we want that? So if you have a readiness check, you need to manually retry within your own check. - is that what we want?
  • is the internal logic around setReadinessChecks good? (and how it overrides and sets the state that it has overridden)
  • General logic around defaultPort adding an implicit readiness check seem reasonable?

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.

1 participant