Skip to content

feat: include healthcheck status in Docker container inspect() result#1348

Open
aleclarson wants to merge 2 commits intoalchemy-run:mainfrom
aleclarson:feat/docker-container-healthcheck
Open

feat: include healthcheck status in Docker container inspect() result#1348
aleclarson wants to merge 2 commits intoalchemy-run:mainfrom
aleclarson:feat/docker-container-healthcheck

Conversation

@aleclarson
Copy link
Contributor

@aleclarson aleclarson commented Feb 26, 2026

Feel free to edit this one as you see fit!

Summary

This PR introduces support for monitoring and waiting on Docker container health checks. It updates the internal Docker API types to expose health status and adds a new method to the Container resource to synchronize actions based on a container's health state.

Key Changes

  • API Enhancements: Updated ContainerState to include the Health object, which tracks status (starting, healthy, unhealthy), failure counts, and log output.
  • New Method: waitForHealth(): Added a method to the Container class that polls the container's state until it reports as healthy.
    • Throws an error if the container is marked unhealthy.
    • Throws an error if the container does not have a health check configured.
  • Testing: Added a comprehensive test suite in container.test.ts to verify the inspection logic and waitForHealth behavior across various states (healthy, unhealthy, starting, and unconfigured).

Impact

This allows users to ensure a service inside a container is fully operational and passed its internal health checks before proceeding with dependent tasks, rather than relying solely on the container's "running" status.

* feat: include healthcheck status in Docker container inspect() result

Co-authored-by: aleclarson <1925840+aleclarson@users.noreply.github.com>

* test(docker): use spyOn exec instead of mocking DockerApi module

Refactor test to spy on DockerApi.prototype.exec instead of mocking the entire module, ensuring better coverage of internal logic while simulating CLI output.

Co-authored-by: aleclarson <1925840+aleclarson@users.noreply.github.com>

* test(docker): switch to real docker tests with safe failure mode

Replace mocked tests with real Docker container tests using busybox, handling environment limitations like rate limits gracefully.

Co-authored-by: aleclarson <1925840+aleclarson@users.noreply.github.com>

* feat(docker): add waitForHealth method to Container resource

Add waitForHealth method to Container resource to allow waiting for healthy status, and update tests to use it.

Co-authored-by: aleclarson <1925840+aleclarson@users.noreply.github.com>

* refactor(docker): hoist container methods to avoid duplication

Hoist inspect and waitForHealth methods in Container resource implementation to avoid code duplication across execution branches.

Co-authored-by: aleclarson <1925840+aleclarson@users.noreply.github.com>

* feat(docker): update waitForHealth to return runtime info

Update waitForHealth to return ContainerRuntimeInfo on success, providing immediate access to container details.

Co-authored-by: aleclarson <1925840+aleclarson@users.noreply.github.com>

* chore: prevent API drift

* chore: revert name change

* chore: revert tsconfig change

---------

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
@pkg-pr-new
Copy link

pkg-pr-new bot commented Feb 26, 2026

Open in StackBlitz

npm i https://pkg.pr.new/alchemy-run/alchemy@1348

commit: 4c2e1c5

@aleclarson aleclarson changed the title feat: include healthcheck status in Docker container inspect() result (#8) feat: include healthcheck status in Docker container inspect() result Feb 26, 2026
Comment on lines +343 to +372
const waitForHealth: Container["waitForHealth"] = async (
timeout = 60000,
) => {
const startTime = Date.now();
while (Date.now() - startTime < timeout) {
const [info] = await api.inspectContainer(containerName);
if (!info) {
throw new Error(`Container ${containerName} not found`);
}

const health = info.State.Health?.Status;
if (health === "healthy") {
return toRuntimeInfo(info);
}
if (health === "unhealthy") {
throw new Error(`Container ${containerName} is unhealthy`);
}
if (!health || health === "none") {
throw new Error(
`Container ${containerName} has no healthcheck configured`,
);
}

// Wait 500ms before next check
await new Promise((resolve) => setTimeout(resolve, 500));
}
throw new Error(
`Timed out waiting for container ${containerName} to become healthy`,
);
};
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if waitForHealth makes sense as an alchemy feature.

  1. a service can be unhealthy and then transition to healthy (which might not make sense here) so throwing an error on unhealthy seems a little bit unexpected.
  2. I think wait for checks often have enough logic tied into them that a generic solution might not be great (e.g. timeout being 500)
  3. this almost makes more sense as part of the resources creation lifecycle rather than a method on it.

Could you briefly explain why you want this as part of alchemy?

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