Files
yusing 6528fb0a8d refactor: propagate context and standardize HTTP client timeouts
Add context parameter to TCP/UDP stream health checks and client constructors
for proper cancellation and deadline propagation. Switch from encoding/json
to sonic for faster JSON unmarshaling.

Standardize HTTP client timeouts to 5 seconds
across agent pool and health check.
2026-01-30 00:23:03 +08:00
..

Health Check Package

Low-level health check implementations for different protocols and services in GoDoxy.

Overview

Purpose

This package provides health check implementations for various protocols:

  • HTTP/HTTPS - Standard HTTP health checks with fasthttp
  • H2C - HTTP/2 cleartext health checks
  • Docker - Container health status via Docker API
  • FileServer - Directory accessibility checks
  • Stream - Generic network connection checks

Primary Consumers

  • internal/health/monitor/ - Route health monitoring
  • internal/metrics/uptime/ - Uptime poller integration

Non-goals

  • Complex health check logic (response body validation, etc.)
  • Authentication/authorization in health checks
  • Multi-step health checks (login then check)

Stability

Internal package. Public functions are stable but may be extended with new parameters.

Public API

HTTP Health Check (http.go)

func HTTP(
    url *url.URL,
    method string,
    path string,
    timeout time.Duration,
) (types.HealthCheckResult, error)

H2C Health Check (http.go)

func H2C(
    ctx context.Context,
    url *url.URL,
    method string,
    path string,
    timeout time.Duration,
) (types.HealthCheckResult, error)

Docker Health Check (docker.go)

func Docker(
    ctx context.Context,
    containerID string,
) (types.HealthCheckResult, error)

FileServer Health Check (fileserver.go)

func FileServer(
    url *url.URL,
) (types.HealthCheckResult, error)

Stream Health Check (stream.go)

func Stream(
    url *url.URL,
) (types.HealthCheckResult, error)

Common Types (internal/types/)

type HealthCheckResult struct {
    Healthy  bool
    Latency  time.Duration
    Detail   string
}

type HealthStatus int

const (
    StatusHealthy   HealthStatus = 0
    StatusUnhealthy HealthStatus = 1
    StatusError     HealthStatus = 2
)

Architecture

HTTP Health Check Flow

flowchart TD
    A[HTTP Health Check] --> B[Create FastHTTP Request]
    B --> C[Set Headers and Method]
    C --> D[Execute Request with Timeout]
    D --> E{Request Successful?}

    E -->|no| F{Error Type}
    F -->|TLS Error| G[Healthy: TLS Error Ignored]
    F -->|Other Error| H[Unhealthy: Error Details]

    E -->|yes| I{Status Code}
    I -->|5xx| J[Unhealthy: Server Error]
    I -->|Other| K[Healthy]

    G --> L[Return Result with Latency]
    H --> L
    J --> L
    K --> L

Docker Health Check Flow

flowchart TD
    A[Docker Health Check] --> B{Docker Failures > Threshold?}
    B -->|yes| C[Return Error: Too Many Failures]
    B -->|no| D[Container Inspect API Call]
    D --> E{Inspect Successful?}
    E -->|no| F[Increment Failure Count]
    E -->|yes| G[Parse Container State]

    G --> H{Container Status}
    H -->|dead/exited/paused/restarting/removing| I[Unhealthy: Container State]
    H -->|created| J[Unhealthy: Not Started]
    H -->|running| K{Health Check Configured?}

    K -->|no| L[Return Error: No Health Check]
    K -->|yes| M[Check Health Status]
    M --> N{Health Status}
    N -->|healthy| O[Healthy]
    N -->|unhealthy| P[Unhealthy: Last Log Output]

    I --> Q[Reset Failure Count]
    J --> Q
    O --> Q
    P --> Q

H2C Health Check Flow

flowchart TD
    A[H2C Health Check] --> B[Create HTTP/2 Transport]
    B --> C[Set AllowHTTP: true]
    C --> D[Create HTTP Request]
    D --> E[Set Headers and Method]
    E --> F[Execute Request with Timeout]
    F --> G{Request Successful?}

    G -->|no| H[Unhealthy: Error Details]
    G -->|yes| I[Check Status Code]
    I --> J{Status Code}
    J -->|5xx| K[Unhealthy: Server Error]
    J -->|Other| L[Healthy]

    H --> M[Return Result with Latency]
    K --> M
    L --> M

FileServer Health Check Flow

flowchart TD
    A[FileServer Health Check] --> B[Start Timer]
    B --> C[Stat Directory Path]
    C --> D{Directory Exists?}

    D -->|no| E[Unhealthy: Path Not Found]
    D -->|yes| F[Healthy: Directory Accessible]
    D -->|error| G[Return Error]

    E --> H[Return Result with Latency]
    F --> H
    G --> I[Return Error]

Stream Health Check Flow

flowchart TD
    A[Stream Health Check] --> B[Create Dialer]
    B --> C[Set Timeout and Fallback Delay]
    C --> D[Start Timer]
    D --> E[Dial Network Connection]
    E --> F{Connection Successful?}

    F -->|no| G{Error Type}
    G -->|Connection Errors| H[Unhealthy: Connection Failed]
    G -->|Other Error| I[Return Error]

    F -->|yes| J[Close Connection]
    J --> K[Healthy: Connection Established]

    H --> L[Return Result with Latency]
    K --> L

Configuration Surface

No explicit configuration per health check. Parameters are passed directly:

Check Type Parameters
HTTP URL, Method, Path, Timeout
H2C Context, URL, Method, Path, Timeout
Docker Context, ContainerID
FileServer URL (path component used)
Stream URL (scheme, host, port used)

HTTP Headers

All HTTP/H2C checks set:

  • User-Agent: GoDoxy/<version>
  • Accept: text/plain,text/html,*/*;q=0.8
  • Accept-Encoding: identity
  • Cache-Control: no-cache
  • Pragma: no-cache

Dependency and Integration Map

External Dependencies

  • github.com/valyala/fasthttp - High-performance HTTP client
  • golang.org/x/net/http2 - HTTP/2 transport
  • Docker socket (for Docker health check)

Internal Dependencies

  • internal/types/ - Health check result types
  • goutils/version/ - User-Agent version

Observability

Logs

No direct logging in health check implementations. Errors are returned as part of HealthCheckResult.Detail.

Metrics

  • Check latency (returned in result)
  • Success/failure rates (tracked by caller)

Security Considerations

  • TLS certificate verification skipped (InsecureSkipVerify: true)
  • Docker socket access required for Docker health check
  • No authentication in health check requests
  • User-Agent identifies GoDoxy for server-side filtering

Failure Modes and Recovery

HTTP/H2C

Failure Mode Result Notes
Connection timeout Unhealthy Detail: timeout message
TLS certificate error Healthy Handled gracefully
5xx response Unhealthy Detail: status text
4xx response Healthy Client error considered healthy

Docker

Failure Mode Result Notes
API call failure Error Throws error to caller
Container not running Unhealthy State: "Not Started"
Container dead/exited Unhealthy State logged
No health check configured Error Requires health check in image

FileServer

Failure Mode Result Notes
Path not found Unhealthy Detail: "path not found"
Permission denied Error Returned to caller
Other OS error Error Returned to caller

Stream

Failure Mode Result Notes
Connection refused Unhealthy Detail: error message
Network unreachable Unhealthy Detail: error message
DNS resolution failure Unhealthy Detail: error message
Context deadline Unhealthy Detail: timeout

Usage Examples

HTTP Health Check

url, _ := url.Parse("http://localhost:8080/health")
result, err := healthcheck.HTTP(url, "GET", "/health", 10*time.Second)
if err != nil {
    fmt.Printf("Error: %v\n", err)
}
fmt.Printf("Healthy: %v, Latency: %v, Detail: %s\n",
    result.Healthy, result.Latency, result.Detail)

H2C Health Check

ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()

url, _ := url.Parse("h2c://localhost:8080")
result, err := healthcheck.H2C(ctx, url, "GET", "/health", 10*time.Second)

Docker Health Check

ctx := context.Background()
result, err := healthcheck.Docker(ctx, "abc123def456")

FileServer Health Check

url, _ := url.Parse("file:///var/www/html")
result, err := healthcheck.FileServer(url)

Stream Health Check

url, _ := url.Parse("tcp://localhost:5432")
result, err := healthcheck.Stream(url)

Testing Notes

  • Unit tests for each health check type
  • Mock Docker server for Docker health check tests
  • Integration tests require running services
  • Timeout handling tests