server

package
v0.0.122 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 30, 2025 License: MIT Imports: 23 Imported by: 0

README

Server Package

Production-ready HTTP server manager with graceful shutdown, request draining, and comprehensive TLS/HTTPS support.

Features

Multiple Server Management - Run multiple HTTP/HTTPS servers concurrently ✅ Graceful Shutdown - Handles SIGINT/SIGTERM with request draining ✅ Automatic Request Rejection - New requests get 503 during shutdown ✅ Health & Readiness Endpoints - Kubernetes-ready health checks ✅ Shutdown Callbacks - Register cleanup functions (DB, cache, metrics) ✅ Comprehensive TLS Support:

  • Certificate files (production)
  • Self-signed certificates (development/testing)
  • Let's Encrypt / AutoTLS (automatic certificate management) ✅ GZIP Compression - Optional response compression ✅ Panic Recovery - Automatic panic recovery middleware ✅ Configurable Timeouts - Read, write, idle, drain, and shutdown timeouts

Quick Start

Single Server
import "github.com/bitechdev/ResolveSpec/pkg/server"

// Create server manager
mgr := server.NewManager()

// Add server
_, err := mgr.Add(server.Config{
    Name:    "api-server",
    Host:    "localhost",
    Port:    8080,
    Handler: myRouter,
    GZIP:    true,
})

// Start and wait for shutdown signal
if err := mgr.ServeWithGracefulShutdown(); err != nil {
    log.Fatal(err)
}
Multiple Servers
mgr := server.NewManager()

// Public API
mgr.Add(server.Config{
    Name:    "public-api",
    Port:    8080,
    Handler: publicRouter,
})

// Admin API
mgr.Add(server.Config{
    Name:    "admin-api",
    Port:    8081,
    Handler: adminRouter,
})

// Start all and wait
mgr.ServeWithGracefulShutdown()

HTTPS/TLS Configuration

Option 1: Certificate Files (Production)
mgr.Add(server.Config{
    Name:    "https-server",
    Host:    "0.0.0.0",
    Port:    443,
    Handler: handler,
    SSLCert: "/etc/ssl/certs/server.crt",
    SSLKey:  "/etc/ssl/private/server.key",
})
Option 2: Self-Signed Certificate (Development)
mgr.Add(server.Config{
    Name:          "dev-server",
    Host:          "localhost",
    Port:          8443,
    Handler:       handler,
    SelfSignedSSL: true,  // Auto-generates certificate
})
Option 3: Let's Encrypt / AutoTLS (Production)
mgr.Add(server.Config{
    Name:            "prod-server",
    Host:            "0.0.0.0",
    Port:            443,
    Handler:         handler,
    AutoTLS:         true,
    AutoTLSDomains:  []string{"example.com", "www.example.com"},
    AutoTLSEmail:    "admin@example.com",
    AutoTLSCacheDir: "./certs-cache",  // Certificate cache directory
})

Configuration

server.Config{
    // Basic configuration
    Name:        "my-server",        // Server name (required)
    Host:        "0.0.0.0",          // Bind address
    Port:        8080,               // Port (required)
    Handler:     myRouter,           // HTTP handler (required)
    Description: "My API server",    // Optional description

    // Features
    GZIP: true,                      // Enable GZIP compression

    // TLS/HTTPS (choose one option)
    SSLCert:         "/path/to/cert.pem",  // Certificate file
    SSLKey:          "/path/to/key.pem",   // Key file
    SelfSignedSSL:   false,                // Auto-generate self-signed cert
    AutoTLS:         false,                // Let's Encrypt
    AutoTLSDomains:  []string{},           // Domains for AutoTLS
    AutoTLSEmail:    "",                   // Email for Let's Encrypt
    AutoTLSCacheDir: "./certs-cache",      // Cert cache directory

    // Timeouts
    ShutdownTimeout: 30 * time.Second,     // Max shutdown time
    DrainTimeout:    25 * time.Second,     // Request drain timeout
    ReadTimeout:     15 * time.Second,     // Request read timeout
    WriteTimeout:    15 * time.Second,     // Response write timeout
    IdleTimeout:     60 * time.Second,     // Idle connection timeout
}

Graceful Shutdown

mgr := server.NewManager()

// Add servers...

// This blocks until SIGINT/SIGTERM
mgr.ServeWithGracefulShutdown()
Manual Control
mgr := server.NewManager()

// Add and start servers
mgr.StartAll()

// Later... stop gracefully
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()

if err := mgr.StopAllWithContext(ctx); err != nil {
    log.Printf("Shutdown error: %v", err)
}
Shutdown Callbacks

Register cleanup functions to run during shutdown:

// Close database
mgr.RegisterShutdownCallback(func(ctx context.Context) error {
    log.Println("Closing database...")
    return db.Close()
})

// Flush metrics
mgr.RegisterShutdownCallback(func(ctx context.Context) error {
    log.Println("Flushing metrics...")
    return metrics.Flush(ctx)
})

// Close cache
mgr.RegisterShutdownCallback(func(ctx context.Context) error {
    log.Println("Closing cache...")
    return cache.Close()
})

Health Checks

Adding Health Endpoints
instance, _ := mgr.Add(server.Config{
    Name:    "api-server",
    Port:    8080,
    Handler: router,
})

// Add health endpoints to your router
router.HandleFunc("/health", instance.HealthCheckHandler())
router.HandleFunc("/ready", instance.ReadinessHandler())
Health Endpoint

Returns server health status:

Healthy (200 OK):

{"status":"healthy"}

Shutting Down (503 Service Unavailable):

{"status":"shutting_down"}
Readiness Endpoint

Returns readiness with in-flight request count:

Ready (200 OK):

{"ready":true,"in_flight_requests":12}

Not Ready (503 Service Unavailable):

{"ready":false,"reason":"shutting_down"}

Shutdown Behavior

When a shutdown signal (SIGINT/SIGTERM) is received:

  1. Mark as shutting down → New requests get 503
  2. Execute callbacks → Run cleanup functions
  3. Drain requests → Wait up to DrainTimeout for in-flight requests
  4. Shutdown servers → Close listeners and connections
Time   Event
─────────────────────────────────────────
0s     Signal received: SIGTERM
       ├─ Mark servers as shutting down
       ├─ Reject new requests (503)
       └─ Execute shutdown callbacks

1s     Callbacks complete
       └─ Start draining requests...

2s     In-flight: 50 requests
3s     In-flight: 32 requests
4s     In-flight: 12 requests
5s     In-flight: 3 requests
6s     In-flight: 0 requests ✓
       └─ All requests drained

6s     Shutdown servers
7s     All servers stopped ✓

Server Management

Get Server Instance
instance, err := mgr.Get("api-server")
if err != nil {
    log.Fatal(err)
}

// Check status
fmt.Printf("Address: %s\n", instance.Addr())
fmt.Printf("Name: %s\n", instance.Name())
fmt.Printf("In-flight: %d\n", instance.InFlightRequests())
fmt.Printf("Shutting down: %v\n", instance.IsShuttingDown())
List All Servers
instances := mgr.List()
for _, instance := range instances {
    fmt.Printf("Server: %s at %s\n", instance.Name(), instance.Addr())
}
Remove Server
// Stop and remove a server
if err := mgr.Remove("api-server"); err != nil {
    log.Printf("Error removing server: %v", err)
}
Restart All Servers
// Gracefully restart all servers
if err := mgr.RestartAll(); err != nil {
    log.Printf("Error restarting: %v", err)
}

Kubernetes Integration

Deployment with Probes
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
spec:
  replicas: 3
  template:
    spec:
      containers:
      - name: app
        image: myapp:latest
        ports:
        - containerPort: 8080

        # Liveness probe
        livenessProbe:
          httpGet:
            path: /health
            port: 8080
          initialDelaySeconds: 10
          periodSeconds: 10

        # Readiness probe
        readinessProbe:
          httpGet:
            path: /ready
            port: 8080
          initialDelaySeconds: 5
          periodSeconds: 5

        # Graceful shutdown
        lifecycle:
          preStop:
            exec:
              command: ["/bin/sh", "-c", "sleep 5"]

        env:
        - name: SHUTDOWN_TIMEOUT
          value: "30"

      # Allow time for graceful shutdown
      terminationGracePeriodSeconds: 35

Docker Compose

version: '3.8'
services:
  app:
    build: .
    ports:
      - "8080:8080"
    environment:
      - SHUTDOWN_TIMEOUT=30
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
      interval: 10s
      timeout: 5s
      retries: 3
    stop_grace_period: 35s

Complete Example

package main

import (
    "context"
    "log"
    "net/http"
    "time"

    "github.com/bitechdev/ResolveSpec/pkg/server"
)

func main() {
    // Create server manager
    mgr := server.NewManager()

    // Register shutdown callbacks
    mgr.RegisterShutdownCallback(func(ctx context.Context) error {
        log.Println("Cleanup: Closing database...")
        // return db.Close()
        return nil
    })

    // Create router
    router := http.NewServeMux()
    router.HandleFunc("/api/data", dataHandler)

    // Add server
    instance, err := mgr.Add(server.Config{
        Name:            "api-server",
        Host:            "0.0.0.0",
        Port:            8080,
        Handler:         router,
        GZIP:            true,
        ShutdownTimeout: 30 * time.Second,
        DrainTimeout:    25 * time.Second,
    })
    if err != nil {
        log.Fatal(err)
    }

    // Add health endpoints
    router.HandleFunc("/health", instance.HealthCheckHandler())
    router.HandleFunc("/ready", instance.ReadinessHandler())

    // Start and wait for shutdown
    log.Println("Starting server on :8080")
    if err := mgr.ServeWithGracefulShutdown(); err != nil {
        log.Printf("Server stopped: %v", err)
    }

    log.Println("Server shutdown complete")
}

func dataHandler(w http.ResponseWriter, r *http.Request) {
    time.Sleep(100 * time.Millisecond) // Simulate work
    w.WriteHeader(http.StatusOK)
    w.Write([]byte(`{"message":"success"}`))
}

Testing Graceful Shutdown

Test Script
#!/bin/bash

# Start server in background
./myapp &
SERVER_PID=$!

# Wait for server to start
sleep 2

# Send requests
for i in {1..10}; do
    curl http://localhost:8080/api/data &
done

# Wait a bit
sleep 1

# Send shutdown signal
kill -TERM $SERVER_PID

# Try more requests (should get 503)
curl -v http://localhost:8080/api/data

# Wait for server to stop
wait $SERVER_PID
echo "Server stopped gracefully"

Best Practices

  1. Set appropriate timeouts

    • DrainTimeout < ShutdownTimeout
    • ShutdownTimeout < Kubernetes terminationGracePeriodSeconds
  2. Use shutdown callbacks for:

    • Database connections
    • Message queues
    • Metrics flushing
    • Cache shutdown
    • Background workers
  3. Health checks

    • Use /health for liveness (is app alive?)
    • Use /ready for readiness (can app serve traffic?)
  4. Load balancer considerations

    • Set preStop hook in Kubernetes (5-10s delay)
    • Allows load balancer to deregister before shutdown
  5. HTTPS in production

    • Use AutoTLS for public-facing services
    • Use certificate files for enterprise PKI
    • Use self-signed only for development/testing
  6. Monitoring

    • Track in-flight requests in metrics
    • Alert on slow drains
    • Monitor shutdown duration

Troubleshooting

Shutdown Takes Too Long
// Increase drain timeout
config.DrainTimeout = 60 * time.Second
config.ShutdownTimeout = 65 * time.Second
Requests Timing Out
// Increase write timeout
config.WriteTimeout = 30 * time.Second
Certificate Issues
// Verify certificate files exist and are readable
if _, err := os.Stat(config.SSLCert); err != nil {
    log.Fatalf("Certificate not found: %v", err)
}

// For AutoTLS, ensure:
// - Port 443 is accessible
// - Domains resolve to server IP
// - Cache directory is writable
Debug Logging
import "github.com/bitechdev/ResolveSpec/pkg/logger"

// Enable debug logging
logger.SetLevel("debug")

API Reference

Manager Methods
  • NewManager() - Create new server manager
  • Add(cfg Config) - Register server instance
  • Get(name string) - Get server by name
  • Remove(name string) - Stop and remove server
  • StartAll() - Start all registered servers
  • StopAll() - Stop all servers gracefully
  • StopAllWithContext(ctx) - Stop with timeout
  • RestartAll() - Restart all servers
  • List() - Get all server instances
  • ServeWithGracefulShutdown() - Start and block until shutdown
  • RegisterShutdownCallback(cb) - Register cleanup function
Instance Methods
  • Start() - Start the server
  • Stop(ctx) - Stop gracefully
  • Addr() - Get server address
  • Name() - Get server name
  • HealthCheckHandler() - Get health handler
  • ReadinessHandler() - Get readiness handler
  • InFlightRequests() - Get in-flight count
  • IsShuttingDown() - Check shutdown status
  • Wait() - Block until shutdown complete

Documentation

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Config

type Config struct {
	Name        string
	Host        string
	Port        int
	Description string

	// Handler is the http.Handler (e.g., a router) to be served.
	Handler http.Handler

	// GZIP compression support
	GZIP bool

	// TLS/HTTPS configuration options (mutually exclusive)
	// Option 1: Provide certificate and key files directly
	SSLCert string
	SSLKey  string

	// Option 2: Use self-signed certificate (for development/testing)
	// Generates a self-signed certificate automatically if no SSLCert/SSLKey provided
	SelfSignedSSL bool

	// Option 3: Use Let's Encrypt / Certbot for automatic TLS
	// AutoTLS enables automatic certificate management via Let's Encrypt
	AutoTLS bool
	// AutoTLSDomains specifies the domains for Let's Encrypt certificates
	AutoTLSDomains []string
	// AutoTLSCacheDir specifies where to cache certificates (default: "./certs-cache")
	AutoTLSCacheDir string
	// AutoTLSEmail is the email for Let's Encrypt registration (optional but recommended)
	AutoTLSEmail string

	// Graceful shutdown configuration
	// ShutdownTimeout is the maximum time to wait for graceful shutdown
	// Default: 30 seconds
	ShutdownTimeout time.Duration

	// DrainTimeout is the time to wait for in-flight requests to complete
	// before forcing shutdown. Default: 25 seconds
	DrainTimeout time.Duration

	// ReadTimeout is the maximum duration for reading the entire request
	// Default: 15 seconds
	ReadTimeout time.Duration

	// WriteTimeout is the maximum duration before timing out writes of the response
	// Default: 15 seconds
	WriteTimeout time.Duration

	// IdleTimeout is the maximum amount of time to wait for the next request
	// Default: 60 seconds
	IdleTimeout time.Duration
}

Config holds the configuration for a single web server instance.

type Instance added in v0.0.122

type Instance interface {
	// Start begins serving requests. This method should be non-blocking and
	// run the server in a separate goroutine.
	Start() error

	// Stop gracefully shuts down the server without interrupting any active connections.
	// It accepts a context to allow for a timeout.
	Stop(ctx context.Context) error

	// Addr returns the network address the server is listening on.
	Addr() string

	// Name returns the server instance name.
	Name() string

	// HealthCheckHandler returns a handler that responds to health checks.
	// Returns 200 OK when healthy, 503 Service Unavailable when shutting down.
	HealthCheckHandler() http.HandlerFunc

	// ReadinessHandler returns a handler for readiness checks.
	// Includes in-flight request count.
	ReadinessHandler() http.HandlerFunc

	// InFlightRequests returns the current number of in-flight requests.
	InFlightRequests() int64

	// IsShuttingDown returns true if the server is shutting down.
	IsShuttingDown() bool

	// Wait blocks until shutdown is complete.
	Wait()
}

Instance defines the interface for a single server instance. It abstracts the underlying http.Server, allowing for easier management and testing.

type Manager added in v0.0.122

type Manager interface {
	// Add registers a new server instance based on the provided configuration.
	// The server is not started until StartAll or Start is called on the instance.
	Add(cfg Config) (Instance, error)

	// Get returns a server instance by its name.
	Get(name string) (Instance, error)

	// Remove stops and removes a server instance by its name.
	Remove(name string) error

	// StartAll starts all registered server instances that are not already running.
	StartAll() error

	// StopAll gracefully shuts down all running server instances.
	// Executes shutdown callbacks and drains in-flight requests.
	StopAll() error

	// StopAllWithContext gracefully shuts down all running server instances with a context.
	StopAllWithContext(ctx context.Context) error

	// RestartAll gracefully restarts all running server instances.
	RestartAll() error

	// List returns all registered server instances.
	List() []Instance

	// ServeWithGracefulShutdown starts all servers and blocks until a shutdown signal is received.
	// It handles SIGINT and SIGTERM signals and performs graceful shutdown with callbacks.
	ServeWithGracefulShutdown() error

	// RegisterShutdownCallback registers a callback to be called during shutdown.
	// Useful for cleanup tasks like closing database connections, flushing metrics, etc.
	RegisterShutdownCallback(cb ShutdownCallback)
}

Manager defines the interface for a server manager. It is responsible for managing the lifecycle of multiple server instances.

Example (Basic)

ExampleManager_basic demonstrates basic server manager usage

package main

import (
	"fmt"
	"net/http"

	"github.com/bitechdev/ResolveSpec/pkg/server"
)

func main() {
	// Create a server manager
	mgr := server.NewManager()

	// Define a simple handler
	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
		fmt.Fprintln(w, "Hello from server!")
	})

	// Add an HTTP server
	_, err := mgr.Add(server.Config{
		Name:    "api-server",
		Host:    "localhost",
		Port:    8080,
		Handler: handler,
		GZIP:    true, // Enable GZIP compression
	})
	if err != nil {
		panic(err)
	}

	// Start all servers
	if err := mgr.StartAll(); err != nil {
		panic(err)
	}

	// Server is now running...
	// When done, stop gracefully
	if err := mgr.StopAll(); err != nil {
		panic(err)
	}
}
Example (GracefulShutdown)

ExampleManager_gracefulShutdown demonstrates graceful shutdown with callbacks

package main

import (
	"context"
	"fmt"
	"net/http"
	"time"

	"github.com/bitechdev/ResolveSpec/pkg/server"
)

func main() {
	mgr := server.NewManager()

	// Register shutdown callbacks for cleanup tasks
	mgr.RegisterShutdownCallback(func(ctx context.Context) error {
		fmt.Println("Closing database connections...")
		// Close your database here
		return nil
	})

	mgr.RegisterShutdownCallback(func(ctx context.Context) error {
		fmt.Println("Flushing metrics...")
		// Flush metrics here
		return nil
	})

	// Add server with custom timeouts
	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// Simulate some work
		time.Sleep(100 * time.Millisecond)
		fmt.Fprintln(w, "Done!")
	})

	_, err := mgr.Add(server.Config{
		Name:            "api-server",
		Host:            "localhost",
		Port:            8080,
		Handler:         handler,
		ShutdownTimeout: 30 * time.Second, // Max time for shutdown
		DrainTimeout:    25 * time.Second, // Time to wait for in-flight requests
		ReadTimeout:     10 * time.Second,
		WriteTimeout:    10 * time.Second,
		IdleTimeout:     120 * time.Second,
	})
	if err != nil {
		panic(err)
	}

	// Start servers and block until shutdown signal (SIGINT/SIGTERM)
	// This will automatically handle graceful shutdown with callbacks
	if err := mgr.ServeWithGracefulShutdown(); err != nil {
		fmt.Printf("Shutdown completed: %v\n", err)
	}
}
Example (HealthChecks)

ExampleManager_healthChecks demonstrates health and readiness endpoints

package main

import (
	"fmt"
	"net/http"

	"github.com/bitechdev/ResolveSpec/pkg/server"
)

func main() {
	mgr := server.NewManager()

	// Create a router with health endpoints
	mux := http.NewServeMux()
	mux.HandleFunc("/api/data", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintln(w, "Data endpoint")
	})

	// Add server
	instance, err := mgr.Add(server.Config{
		Name:    "api-server",
		Host:    "localhost",
		Port:    8080,
		Handler: mux,
	})
	if err != nil {
		panic(err)
	}

	// Add health and readiness endpoints
	mux.HandleFunc("/health", instance.HealthCheckHandler())
	mux.HandleFunc("/ready", instance.ReadinessHandler())

	// Start the server
	if err := mgr.StartAll(); err != nil {
		panic(err)
	}

	// Health check returns:
	// - 200 OK with {"status":"healthy"} when healthy
	// - 503 Service Unavailable with {"status":"shutting_down"} when shutting down

	// Readiness check returns:
	// - 200 OK with {"ready":true,"in_flight_requests":N} when ready
	// - 503 Service Unavailable with {"ready":false,"reason":"shutting_down"} when shutting down

	// Cleanup
	mgr.StopAll()
}
Example (Https)

ExampleManager_https demonstrates HTTPS configurations

package main

import (
	"fmt"
	"net/http"

	"github.com/bitechdev/ResolveSpec/pkg/server"
)

func main() {
	mgr := server.NewManager()
	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintln(w, "Secure connection!")
	})

	// Option 1: Use certificate files
	_, err := mgr.Add(server.Config{
		Name:    "https-server-files",
		Host:    "localhost",
		Port:    8443,
		Handler: handler,
		SSLCert: "/path/to/cert.pem",
		SSLKey:  "/path/to/key.pem",
	})
	if err != nil {
		panic(err)
	}

	// Option 2: Self-signed certificate (for development)
	_, err = mgr.Add(server.Config{
		Name:          "https-server-self-signed",
		Host:          "localhost",
		Port:          8444,
		Handler:       handler,
		SelfSignedSSL: true,
	})
	if err != nil {
		panic(err)
	}

	// Option 3: Let's Encrypt / AutoTLS (for production)
	_, err = mgr.Add(server.Config{
		Name:            "https-server-letsencrypt",
		Host:            "0.0.0.0",
		Port:            443,
		Handler:         handler,
		AutoTLS:         true,
		AutoTLSDomains:  []string{"example.com", "www.example.com"},
		AutoTLSEmail:    "admin@example.com",
		AutoTLSCacheDir: "./certs-cache",
	})
	if err != nil {
		panic(err)
	}

	// Start all servers
	if err := mgr.StartAll(); err != nil {
		panic(err)
	}

	// Cleanup
	mgr.StopAll()
}
Example (Monitoring)

ExampleManager_monitoring demonstrates monitoring server state

package main

import (
	"fmt"
	"net/http"
	"time"

	"github.com/bitechdev/ResolveSpec/pkg/server"
)

func main() {
	mgr := server.NewManager()

	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		time.Sleep(50 * time.Millisecond) // Simulate work
		fmt.Fprintln(w, "Done")
	})

	instance, err := mgr.Add(server.Config{
		Name:    "api-server",
		Host:    "localhost",
		Port:    8080,
		Handler: handler,
	})
	if err != nil {
		panic(err)
	}

	if err := mgr.StartAll(); err != nil {
		panic(err)
	}

	// Check server status
	fmt.Printf("Server address: %s\n", instance.Addr())
	fmt.Printf("Server name: %s\n", instance.Name())
	fmt.Printf("Is shutting down: %v\n", instance.IsShuttingDown())
	fmt.Printf("In-flight requests: %d\n", instance.InFlightRequests())

	// Cleanup
	mgr.StopAll()

	// Wait for complete shutdown
	instance.Wait()
}
Example (MultipleServers)

ExampleManager_multipleServers demonstrates running multiple servers

package main

import (
	"fmt"
	"net/http"

	"github.com/bitechdev/ResolveSpec/pkg/server"
)

func main() {
	mgr := server.NewManager()

	// Public API server
	publicHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintln(w, "Public API")
	})
	_, err := mgr.Add(server.Config{
		Name:    "public-api",
		Host:    "0.0.0.0",
		Port:    8080,
		Handler: publicHandler,
		GZIP:    true,
	})
	if err != nil {
		panic(err)
	}

	// Admin API server (different port)
	adminHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintln(w, "Admin API")
	})
	_, err = mgr.Add(server.Config{
		Name:    "admin-api",
		Host:    "localhost",
		Port:    8081,
		Handler: adminHandler,
	})
	if err != nil {
		panic(err)
	}

	// Metrics server (internal only)
	metricsHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintln(w, "Metrics data")
	})
	_, err = mgr.Add(server.Config{
		Name:    "metrics",
		Host:    "127.0.0.1",
		Port:    9090,
		Handler: metricsHandler,
	})
	if err != nil {
		panic(err)
	}

	// Start all servers at once
	if err := mgr.StartAll(); err != nil {
		panic(err)
	}

	// Get specific server instance
	publicInstance, err := mgr.Get("public-api")
	if err != nil {
		panic(err)
	}
	fmt.Printf("Public API running on: %s\n", publicInstance.Addr())

	// List all servers
	instances := mgr.List()
	fmt.Printf("Running %d servers\n", len(instances))

	// Stop all servers gracefully (in parallel)
	if err := mgr.StopAll(); err != nil {
		panic(err)
	}
}

func NewManager added in v0.0.122

func NewManager() Manager

NewManager creates a new server manager.

type ShutdownCallback

type ShutdownCallback func(context.Context) error

ShutdownCallback is a function called during graceful shutdown.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL