feat(health): gate connection info on container health check#39
Draft
shiftysheep wants to merge 6 commits intomasterfrom
Draft
feat(health): gate connection info on container health check#39shiftysheep wants to merge 6 commits intomasterfrom
shiftysheep wants to merge 6 commits intomasterfrom
Conversation
added 6 commits
March 2, 2026 17:41
Add a lazy health-check gate that delays showing connection info until Docker confirms the container/service is accepting connections. - Model: add `healthy` Boolean column to DockerChallengeTracker (default False for new inserts; server_default 1 preserves existing rows) - Migration: _ensure_healthy_column() adds the column on plugin upgrade - Functions: add get_container_states(), get_service_states(), and _CachedDockerState (5s TTL) for batched Docker API calls — O(1) calls per poll window regardless of user count - API: DockerStatus.get() checks health via batched state lookup; returns status='starting' (no ports/host) or status='running' (with connection info); cleans up dead tracker entries - Frontend: containerStarting state shows spinner with 3s rapid poll during startup; connection info appears only once status='running' - Tests: 30 new tests covering state mapping, cache TTL, and API endpoint behaviour for starting/running/dead container scenarios
…t dead Container state mapping was too aggressive: - 'created' state (Docker container just started) mapped to 'stopped' → deletion - '' (not found in states dict) also triggered deletion Fixes: - _fetch_container_states: map 'created'/'restarting' to 'starting'; only 'exited'/'dead'/'removing'/'paused' map to 'stopped' - _process_unhealthy_entry: treat '' (not found) as 'starting' — container may simply not be visible in Docker yet immediately after creation - Tests updated + new test for not-found-shows-starting behaviour
When a service exists on Docker but the tracker entry is gone (e.g. after CTFd restart with in-flight containers), creation returns 409. Previously this silently returned (None, None) → 500 to the user. Now mirrors the find_existing() pattern used by create_container(): on 409, query the existing service by name and return its ID and actual port configuration so the tracker entry can be recreated.
…sponses requests.Response.__bool__ returns False for any 4xx response, so 'if not r:' was short-circuiting the 409 conflict-recovery code before it could fire. Both create_service and create_container were affected. Change 'if not r:' to 'if r is None:' so only true network failures (where do_request returns None) trigger the early return, while 409 responses correctly fall through to the name-conflict recovery path.
Adds a Status column to the admin docker status table showing 'Running' (green) or 'Starting' (yellow) based on the healthy flag. No backend changes required — healthy is already in the tracker model.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
healthycolumn toDockerChallengeTracker; new containers start withhealthy=Falseso connection info is withheld until Docker confirms they're runningstatus: "starting"(no ports/host) orstatus: "running"(with connection info), backed by a batched Docker state fetch with 5s TTL cachecreate_servicereturning 500 on name conflicts: recovers the existing service ID on Docker 409 (mirrors existingcreate_containerbehaviour), and fixes the underlyingif not r:bug that was swallowing 4xx responses before status checks could fireChanges
5dba0f49b6dbaeengine.begin())8aa440acreated/not-found containers asstarting, not deadb615ce7823610dif not r:swallowed 4xx before 409 check could firedcfa67dTest plan
/admin/docker_statusshows Running / Starting badge per containerpytest tests/ -v— all 282 tests passpre-commit run --all-files— all checks pass