Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 0 additions & 88 deletions op-conductor/client/mocks/RollupBoostClient.go

This file was deleted.

89 changes: 89 additions & 0 deletions op-conductor/client/mocks/RollupBoostHealthChecker.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const (
HealthzEndpoint = "/healthz"
)

// HealthStatus represents the health state of rollup-boost.
type HealthStatus string

const (
Expand All @@ -20,26 +21,32 @@ const (
HealthStatusUnhealthy HealthStatus = "unhealthy"
)

type RollupBoostClient interface {
// RollupBoostHealthChecker is the common interface for rollup-boost health checking.
// Both RollupBoostClient and RollupBoostNextClient implement this interface.
type RollupBoostHealthChecker interface {
Healthcheck(ctx context.Context) (HealthStatus, error)
}

type rollupBoostClient struct {
// RollupBoostClient uses HTTP status codes to determine rollup-boost health.
type RollupBoostClient struct {
baseURL string
httpClient *http.Client
}

func NewRollupBoostClient(baseURL string, httpClient *http.Client) RollupBoostClient {
// NewRollupBoostClient creates a client that interprets HTTP status codes for health.
func NewRollupBoostClient(baseURL string, httpClient *http.Client) *RollupBoostClient {
if httpClient == nil {
httpClient = http.DefaultClient
}
return &rollupBoostClient{
return &RollupBoostClient{
baseURL: baseURL,
httpClient: httpClient,
}
}

func (c *rollupBoostClient) Healthcheck(ctx context.Context) (HealthStatus, error) {
// Healthcheck returns health status based on HTTP status codes:
// 200 OK = Healthy, 206 Partial Content = Partial, 503 Service Unavailable = Unhealthy
func (c *RollupBoostClient) Healthcheck(ctx context.Context) (HealthStatus, error) {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, c.baseURL+HealthzEndpoint, nil)
if err != nil {
return "", fmt.Errorf("failed to create request: %w", err)
Expand All @@ -65,3 +72,6 @@ func (c *rollupBoostClient) Healthcheck(ctx context.Context) (HealthStatus, erro
return "", fmt.Errorf("unexpected status code: %d", resp.StatusCode)
}
}

// Ensure RollupBoostClient implements RollupBoostHealthChecker
var _ RollupBoostHealthChecker = (*RollupBoostClient)(nil)
79 changes: 79 additions & 0 deletions op-conductor/client/rollupboost_next.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package client

import (
"context"
"encoding/json"
"fmt"
"io"
"net/http"
)

// JSON API health status values returned by rollup-boost
const (
jsonHealthStatusHealthy = "Healthy"
jsonHealthStatusPartial = "PartialContent"
jsonHealthStatusUnhealthy = "ServiceUnavailable"
)

// RollupBoostNextClient retrieves rollup-boost health using the JSON-based healthcheck endpoint.
type RollupBoostNextClient struct {
url string
httpClient *http.Client
}

// RollupBoostNextHealthResponse captures the JSON payload returned by the rollup-boost health endpoint.
type RollupBoostNextHealthResponse struct {
Version string `json:"version"`
RollupBoostHealth string `json:"rollup_boost_health"`
}

// NewRollupBoostNextClient constructs a client for querying the rollup-boost health endpoint.
// The url parameter should be the full URL including path (e.g., "http://localhost:8080/healthz").
func NewRollupBoostNextClient(url string, httpClient *http.Client) *RollupBoostNextClient {
if httpClient == nil {
httpClient = http.DefaultClient
}
return &RollupBoostNextClient{
url: url,
httpClient: httpClient,
}
}

// Healthcheck fetches the rollup-boost health endpoint and interprets the JSON payload.
func (c *RollupBoostNextClient) Healthcheck(ctx context.Context) (HealthStatus, error) {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, c.url, nil)
if err != nil {
return "", fmt.Errorf("failed to create request: %w", err)
}

resp, err := c.httpClient.Do(req)
if err != nil {
return "", fmt.Errorf("failed to make request: %w", err)
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
return "", fmt.Errorf("unexpected status code: %d", resp.StatusCode)
}

var payload RollupBoostNextHealthResponse
// Limit response size to 1 MiB to prevent memory exhaustion from malicious servers
if err := json.NewDecoder(io.LimitReader(resp.Body, 1<<20)).Decode(&payload); err != nil {
return "", fmt.Errorf("failed to decode response: %w", err)
}

// Map JSON API values to internal constants
switch payload.RollupBoostHealth {
case jsonHealthStatusHealthy:
return HealthStatusHealthy, nil
case jsonHealthStatusPartial:
return HealthStatusPartial, nil
case jsonHealthStatusUnhealthy:
return HealthStatusUnhealthy, nil
default:
return "", fmt.Errorf("unexpected rollup_boost_health: %q", payload.RollupBoostHealth)
}
}

// Ensure RollupBoostNextClient implements RollupBoostHealthChecker
var _ RollupBoostHealthChecker = (*RollupBoostNextClient)(nil)
Loading