Skip to content

feat(cli): add --health probe and Docker HEALTHCHECK#404

Merged
SantiagoDePolonia merged 3 commits into
mainfrom
feat/healthcheck
Jun 16, 2026
Merged

feat(cli): add --health probe and Docker HEALTHCHECK#404
SantiagoDePolonia merged 3 commits into
mainfrom
feat/healthcheck

Conversation

@SantiagoDePolonia

@SantiagoDePolonia SantiagoDePolonia commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds a --health CLI flag and wires it into the Docker image as a HEALTHCHECK, so orchestrators (Docker, Compose, Kubernetes) can detect an unhealthy gateway without bundling curl/wget into the runtime image.

  • gomodel --health probes the local /health endpoint and exits 0 when status is ok, non-zero otherwise.
  • gomodel --health-timeout <dur> bounds the probe request (default 2s).
  • The probe reuses config.Load, so it honors the configured PORT and BASE_PATH rather than hardcoding an address.
  • CLI parsing moves to a testable FlagSet (parseCLI) that accepts both single- and double-dash flags and reports parse errors via exit code instead of os.Exit.

User-visible impact

  • New --health / --health-timeout flags (documented in README and docs/dev/api-examples.md).
  • Containers now report health status; an unhealthy gateway is surfaced to the orchestrator.
  • No change to the OpenAI-compatible HTTP API.

Tests

  • parseCLI: single/double-dash flags, unknown-flag rejection, exit-code mapping.
  • healthProbeURL: port/base-path composition incl. default-port fallback.
  • checkHealthEndpoint: healthy, bad status code, bad body, unhealthy status.
  • runHealthProbe: end-to-end against an httptest server on the configured port/base path.

All pre-commit hooks pass (make test-race, make lint).

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added gomodel --health for runtime health probing (expects HTTP 200 with {"status":"ok"}) and gomodel --version.
    • Added --health-timeout to control probe timeout.
    • Added a Docker HEALTHCHECK that runs "/gomodel", "--health" in the runtime image.
  • Documentation
    • Updated CLI/health examples and added a new “CLI Operations” guide, including health probe behavior.
  • Tests
    • Added unit tests for CLI flag parsing and health probe URL/endpoint behavior.

Add a `--health` CLI flag that probes the local /health endpoint and exits
non-zero on failure, plus a `--health-timeout` to bound the request. Wire it
into the Dockerfile as a HEALTHCHECK so container orchestrators can detect an
unhealthy gateway without bundling curl/wget into the image.

CLI parsing moves to a testable FlagSet (parseCLI) that accepts both single-
and double-dash flags and reports parse errors via exit code instead of
os.Exit. The probe reuses config.Load so it honors the configured PORT and
BASE_PATH.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds --health and --version CLI flags to the gomodel binary via a new flags.go file, implements an HTTP health probe in health.go that GETs /health, validates a JSON {"status":"ok"} response, and wires both flags into main(). A HEALTHCHECK directive invoking /gomodel --health is added to the Dockerfile, and new documentation covers the CLI flags and Docker usage.

Changes

Health probe CLI feature

Layer / File(s) Summary
CLI flag contract and parsing
cmd/gomodel/flags.go
cliOptions struct holds --version, --health, and --health-timeout (default 2s). parseCLI creates a flag.FlagSet, parses arguments, rejects non-flag trailing positionals, and routes flag output to the provided writer. cliParseExitCode maps flag.ErrHelp to exit 0, other errors to exit 2.
HTTP health probe implementation
cmd/gomodel/health.go
runHealthProbe loads server config, applies a default timeout when needed, and delegates to checkHealthEndpoint. healthProbeURL builds the probe URL to 127.0.0.1 with default port 8080 and the configured base path. checkHealthEndpoint performs a GET request, requires HTTP 200 OK, decodes a 1024-byte-limited JSON body, and validates {"status":"ok"}.
CLI flag and health probe tests
cmd/gomodel/flags_test.go, cmd/gomodel/health_test.go
flags_test.go covers parseCLI accepting single/double-dash forms, rejecting unknown flags and positional arguments, and cliParseExitCode with direct and fmt.Errorf-wrapped flag.ErrHelp. health_test.go validates healthProbeURL URL construction across default/prefixed base paths and port defaults, checkHealthEndpoint HTTP/JSON error conditions, and runHealthProbe end-to-end against an ephemeral httptest server with environment-configured port and base path.
main() entrypoint wiring
cmd/gomodel/main.go
Removes the flag package import and replaces flag-based --version handling with parseCLI(os.Args[1:], os.Stderr). Prints version.Info() and exits 0 on opts.Version. Loads environment variables unconditionally. Runs runHealthProbe(opts.HealthTimeout) when opts.Health is set, printing errors to stderr and exiting 1 on probe failure.
Dockerfile HEALTHCHECK and documentation
Dockerfile, docs/advanced/cli.mdx, docs/docs.json, docs/dev/api-examples.md
Dockerfile adds HEALTHCHECK directive invoking /gomodel --health with interval/timeout/start-period/retry config. New docs/advanced/cli.mdx page documents all flags, health probe behavior (loopback targeting, HTTP 200/JSON validation, exit codes), and Docker usage. docs.json registers the new CLI page in the Advanced navigation group. docs/dev/api-examples.md adds CLI command examples to the Health Check section.

Sequence Diagram(s)

sequenceDiagram
  participant CLI as gomodel binary
  participant parseCLI as parseCLI
  participant runHealthProbe as runHealthProbe
  participant configLoad as config.Load()
  participant checkHealthEndpoint as checkHealthEndpoint
  participant Server as HTTP /health

  CLI->>parseCLI: os.Args[1:], os.Stderr
  parseCLI-->>CLI: cliOptions{Health:true, HealthTimeout}
  CLI->>runHealthProbe: HealthTimeout
  runHealthProbe->>configLoad: Load()
  configLoad-->>runHealthProbe: port, base path
  runHealthProbe->>checkHealthEndpoint: ctx, http.Client, 127.0.0.1:{port}/{base}/health
  checkHealthEndpoint->>Server: GET /health
  Server-->>checkHealthEndpoint: 200 OK {"status":"ok"}
  checkHealthEndpoint-->>runHealthProbe: nil
  runHealthProbe-->>CLI: nil (exit 0)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related issues

Poem

🐇 A health flag hops into the CLI scene,
Pinging /health to keep the server keen.
Exit zero means all is well and bright,
The Dockerfile checks at intervals just right.
No curl needed—the binary knows the way! 🌿

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 9.09% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'feat(cli): add --health probe and Docker HEALTHCHECK' directly and concisely summarizes the main changes: introducing health probe functionality and Docker health checks via new CLI flags.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/healthcheck

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@mintlify

mintlify Bot commented Jun 16, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
gomodel 🟢 Ready View Preview Jun 16, 2026, 9:57 AM

💡 Tip: Enable Workflows to automatically generate PRs for you.

@greptile-apps

greptile-apps Bot commented Jun 16, 2026

Copy link
Copy Markdown

Greptile Summary

This PR adds a built-in container health probe for GoModel. The main changes are:

  • New --health and --health-timeout CLI flags.
  • Config-aware probing of the local /health endpoint.
  • Docker HEALTHCHECK using the GoModel binary.
  • Tests for CLI parsing, health URL construction, and endpoint validation.
  • README and API example updates for the new CLI operations.

Confidence Score: 5/5

This looks safe to merge.

  • No blocking issues found in the changed code.
  • The probe matches the existing /health response contract.
  • The Docker healthcheck uses the same config path and working directory as the application.

Important Files Changed

Filename Overview
cmd/gomodel/health.go Adds config-aware health probing against the existing local health endpoint.
cmd/gomodel/main.go Routes parsed CLI options to version output, health probing, or normal server startup.
Dockerfile Adds an exec-form healthcheck that runs the new built-in probe.

Reviews (1): Last reviewed commit: "feat(cli): add --health probe and Docker..." | Re-trigger Greptile

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cmd/gomodel/flags.go`:
- Around line 18-26: The parseCLI function currently ignores unexpected
positional arguments by returning the result of flags.Parse directly without
validation. After calling flags.Parse(args) in the parseCLI function, add a
check to verify that flags.NArg() is zero. If there are unexpected positional
arguments (when NArg() is greater than 0), return an error with a clear message
instead of silently returning success. This prevents typos and extra arguments
from being silently accepted.

In `@README.md`:
- Around line 279-287: The CLI Operations section in the README.md documentation
is missing documentation for the `--health-timeout` flag. Add a new example line
in the bash code block that demonstrates the `--health-timeout` flag usage with
a timeout value (such as 5s) to make this configuration option discoverable and
show users how to tune the runtime probe timeout behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 1a097b2e-d1e8-4413-9287-329166555843

📥 Commits

Reviewing files that changed from the base of the PR and between 926bb7d and 0856560.

📒 Files selected for processing (8)
  • Dockerfile
  • README.md
  • cmd/gomodel/flags.go
  • cmd/gomodel/flags_test.go
  • cmd/gomodel/health.go
  • cmd/gomodel/health_test.go
  • cmd/gomodel/main.go
  • docs/dev/api-examples.md

Comment thread cmd/gomodel/flags.go
Comment thread README.md Outdated
Comment on lines +279 to +287
### CLI Operations

GoModel accepts both single-dash and double-dash CLI flags. Examples use the
long form:

```bash
gomodel --version
gomodel --health
```

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Document --health-timeout in the CLI section.

The new CLI docs list --version and --health, but omit --health-timeout (including default behavior). Please add it so runtime probe tuning is discoverable.

Suggested patch
 GoModel accepts both single-dash and double-dash CLI flags. Examples use the
 long form:
 
 ```bash
 gomodel --version
 gomodel --health
+gomodel --health --health-timeout=5s
</details>

<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

```suggestion
### CLI Operations

GoModel accepts both single-dash and double-dash CLI flags. Examples use the
long form:

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@README.md` around lines 279 - 287, The CLI Operations section in the
README.md documentation is missing documentation for the `--health-timeout`
flag. Add a new example line in the bash code block that demonstrates the
`--health-timeout` flag usage with a timeout value (such as 5s) to make this
configuration option discoverable and show users how to tune the runtime probe
timeout behavior.

@codecov-commenter

codecov-commenter commented Jun 16, 2026

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

❌ Patch coverage is 70.00000% with 18 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
cmd/gomodel/main.go 0.00% 9 Missing ⚠️
cmd/gomodel/health.go 77.14% 4 Missing and 4 partials ⚠️
cmd/gomodel/flags.go 93.75% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

Add a dedicated Advanced > CLI Operations page documenting --version,
--health, --health-timeout, and the Docker HEALTHCHECK usage, and register
it in the docs navigation. Drop the brief CLI Operations section from the
README so the docs site is the single source of truth.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/advanced/cli.mdx`:
- Around line 40-42: The health probe description in docs/advanced/cli.mdx
(lines 40-42) currently states that the probe "targets the same address the
server listens on," which is misleading because the implementation always
targets loopback (127.0.0.1) and only derives PORT and BASE_PATH from the
configuration, not the host. Revise the sentence to clarify that only the PORT
and BASE_PATH are honored from the server configuration, while the health probe
always targets the loopback interface, making clear that it does not reuse the
full configured listen address.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: a55503c8-d373-435f-a0f5-c40be3139dcb

📥 Commits

Reviewing files that changed from the base of the PR and between 0856560 and 086a6cc.

📒 Files selected for processing (2)
  • docs/advanced/cli.mdx
  • docs/docs.json

Comment thread docs/advanced/cli.mdx Outdated
Address review feedback:
- parseCLI now errors on leftover positional arguments so typoed invocations
  like `gomodel --health extra` fail loudly instead of silently succeeding.
- Clarify in the docs that the health probe always targets loopback
  (127.0.0.1) and only derives PORT/BASE_PATH from config.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cmd/gomodel/flags_test.go`:
- Around line 40-44: The test TestParseCLI_RejectsPositionalArgs only verifies
that an error is returned for positional arguments, but it doesn't verify that
the error maps to the expected exit code 2 (cliParseExitCode). Add an assertion
to check that the returned error from the parseCLI call equals cliParseExitCode,
ensuring the test covers the full contract for parse failures and validates the
non-help branch exit code mapping.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 3e1e6ab2-783a-464d-bf78-0de0484bbe6d

📥 Commits

Reviewing files that changed from the base of the PR and between 086a6cc and 767c3f4.

📒 Files selected for processing (3)
  • cmd/gomodel/flags.go
  • cmd/gomodel/flags_test.go
  • docs/advanced/cli.mdx

Comment thread cmd/gomodel/flags_test.go
Comment on lines +40 to +44
func TestParseCLI_RejectsPositionalArgs(t *testing.T) {
if _, err := parseCLI([]string{"--health", "extra"}, io.Discard); err == nil {
t.Fatal("parseCLI(--health extra) error = nil, want error")
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Assert exit-code mapping for positional-argument parse failures.

Line 41 verifies parse failure, but it doesn’t verify that this failure maps to exit code 2 in the main path (cliParseExitCode). Add an assertion on the returned error to cover that contract and the remaining non-help branch in cmd/gomodel/flags.go.

Suggested patch
 func TestParseCLI_RejectsPositionalArgs(t *testing.T) {
-	if _, err := parseCLI([]string{"--health", "extra"}, io.Discard); err == nil {
+	_, err := parseCLI([]string{"--health", "extra"}, io.Discard)
+	if err == nil {
 		t.Fatal("parseCLI(--health extra) error = nil, want error")
 	}
+	if got := cliParseExitCode(err); got != 2 {
+		t.Fatalf("cliParseExitCode(positional args) = %d, want 2", got)
+	}
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cmd/gomodel/flags_test.go` around lines 40 - 44, The test
TestParseCLI_RejectsPositionalArgs only verifies that an error is returned for
positional arguments, but it doesn't verify that the error maps to the expected
exit code 2 (cliParseExitCode). Add an assertion to check that the returned
error from the parseCLI call equals cliParseExitCode, ensuring the test covers
the full contract for parse failures and validates the non-help branch exit code
mapping.

@SantiagoDePolonia SantiagoDePolonia merged commit 9115c3b into main Jun 16, 2026
19 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