server

package
v1.3.1 Latest Latest
Warning

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

Go to latest
Published: Jan 8, 2026 License: MIT Imports: 10 Imported by: 0

Documentation

Overview

Package server provides utilities for creating and running HTTP servers with environment-based configuration and graceful shutdown handling.

The server package integrates with the config package to automatically load server settings (port, timeouts) from environment variables. It provides graceful shutdown on interrupt signals with proper resource cleanup.

Basic usage:

func main() {
    mux := http.NewServeMux()
    mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("Hello, World!"))
    })

    if err := server.Run(context.Background(), mux); err != nil {
        log.Fatal(err)
    }
}

The Run function handles all server lifecycle management including:

  • Loading configuration from environment variables
  • Starting the HTTP server in a goroutine
  • Listening for interrupt signals (SIGINT, SIGTERM)
  • Performing graceful shutdown with a 10-second timeout

For more control over the server instance, use NewServerWithConfig to create an *http.Server and manage its lifecycle manually.

All functions are safe for concurrent use.

Example

Example demonstrates basic usage of the server package with Run.

package main

import (
	"fmt"
	"net/http"
	"os"
)

func main() {
	// Set environment variables for configuration
	os.Setenv("PORT", "8080")
	os.Setenv("ENVIRONMENT", "local")

	// Create a simple HTTP handler
	mux := http.NewServeMux()
	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("Hello, World!"))
	})

	// Note: In a real application, this would block and run the server
	// For this example, we just demonstrate the API
	fmt.Println("Server would start on port 8080")

	// In production:
	// if err := server.Run(context.Background(), mux); err != nil {
	//     log.Fatal(err)
	// }

}
Output:
Server would start on port 8080

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func NewServerWithConfig

func NewServerWithConfig(handler http.Handler) (*http.Server, error)

NewServerWithConfig creates a new http.Server configured from environment variables.

The server is configured using config.ServerConfig, which loads settings for:

  • Port (env: PORT, default: 8080)
  • ReadTimeout (env: READ_TIMEOUT, default: 5 seconds)
  • WriteTimeout (env: WRITE_TIMEOUT, default: 10 seconds)
  • IdleTimeout (env: IDLE_TIMEOUT, default: 120 seconds)
  • Environment (env: ENVIRONMENT, default: Local)

The function returns an error if the configuration cannot be parsed or validated. Common error cases include invalid port numbers or timeout values.

The returned server is ready to use with ListenAndServe or Shutdown methods. For automatic lifecycle management with graceful shutdown, use the Run function instead.

This function is safe for concurrent use.

Example

ExampleNewServerWithConfig shows how to create a server with custom configuration.

package main

import (
	"fmt"
	"io"
	"log"
	"log/slog"
	"net/http"
	"os"

	"github.com/harrydayexe/GoWebUtilities/server"
)

func main() {
	// Suppress log output for example
	slog.SetDefault(slog.New(slog.NewTextHandler(io.Discard, nil)))

	// Set custom configuration via environment
	os.Setenv("PORT", "3000")
	os.Setenv("READ_TIMEOUT", "30")
	os.Setenv("WRITE_TIMEOUT", "30")
	os.Setenv("ENVIRONMENT", "production")

	// Create a handler
	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
		w.Write([]byte("OK"))
	})

	// Create server with configuration
	srv, err := server.NewServerWithConfig(handler)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("Server configured on %s\n", srv.Addr)
	fmt.Printf("Read timeout: %v\n", srv.ReadTimeout)
	fmt.Printf("Write timeout: %v\n", srv.WriteTimeout)
}
Example (Defaults)

ExampleNewServerWithConfig_defaults shows server creation with default configuration.

package main

import (
	"fmt"
	"io"
	"log"
	"log/slog"
	"net/http"
	"os"

	"github.com/harrydayexe/GoWebUtilities/server"
)

func main() {
	// Suppress log output for example
	slog.SetDefault(slog.New(slog.NewTextHandler(io.Discard, nil)))

	// Clear environment to use defaults
	os.Unsetenv("PORT")
	os.Unsetenv("ENVIRONMENT")
	os.Unsetenv("READ_TIMEOUT")
	os.Unsetenv("WRITE_TIMEOUT")
	os.Unsetenv("IDLE_TIMEOUT")

	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
	})

	srv, err := server.NewServerWithConfig(handler)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("Server address: %s\n", srv.Addr)
	fmt.Printf("Read timeout: %v\n", srv.ReadTimeout)
	fmt.Printf("Idle timeout: %v\n", srv.IdleTimeout)
}
Example (ErrorHandling)

ExampleNewServerWithConfig_errorHandling demonstrates error handling for invalid configuration.

package main

import (
	"fmt"
	"net/http"
	"os"

	"github.com/harrydayexe/GoWebUtilities/server"
)

func main() {
	// Set invalid environment
	os.Setenv("ENVIRONMENT", "staging")

	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})

	srv, err := server.NewServerWithConfig(handler)
	if err != nil {
		fmt.Println("Configuration error occurred")
		fmt.Println("Using fallback configuration")
		// Could create default server or handle error differently
		return
	}

	fmt.Printf("Server created: %v\n", srv)

}
Output:
Configuration error occurred
Using fallback configuration

func Run

func Run(
	ctx context.Context,
	srv http.Handler,
) error

Run starts the HTTP server with the provided handler and manages its lifecycle.

This function handles the complete server lifecycle including:

  • Loading configuration from environment variables via NewServerWithConfig
  • Starting the HTTP server in a background goroutine
  • Listening for interrupt signals (SIGINT) on the provided context
  • Performing graceful shutdown with a 10-second timeout when interrupted

The function blocks until the server is shut down, either by:

  • An interrupt signal (Ctrl+C)
  • Cancellation of the provided context
  • A fatal error during server creation

Returns an error only if server creation fails (e.g., invalid configuration). Errors during ListenAndServe or Shutdown are logged to stderr but do not cause the function to return an error, as they may occur during normal shutdown.

Example usage:

mux := http.NewServeMux()
mux.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
    w.WriteHeader(http.StatusOK)
})
if err := server.Run(context.Background(), mux); err != nil {
    log.Fatal(err)
}

This function is safe for concurrent use.

Example

ExampleRun shows the complete pattern for running a server with graceful shutdown.

package main

import (
	"fmt"
	"net/http"
	"os"
)

func main() {
	// For example purposes, we'll demonstrate the pattern
	// without actually starting a long-running server

	// Set configuration
	os.Setenv("PORT", "8080")
	os.Setenv("ENVIRONMENT", "local")

	// Create handler
	mux := http.NewServeMux()
	mux.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
		w.Write([]byte("healthy"))
	})

	fmt.Println("Server configuration loaded")
	fmt.Println("Handler registered at /health")
	fmt.Println("Server would run until interrupted (Ctrl+C)")

	// In production:
	// if err := server.Run(context.Background(), mux); err != nil {
	//     log.Fatal(err)
	// }

}
Output:
Server configuration loaded
Handler registered at /health
Server would run until interrupted (Ctrl+C)
Example (HealthCheck)

ExampleRun_healthCheck demonstrates a realistic health check endpoint pattern.

package main

import (
	"fmt"
	"net/http"
	"os"
)

func main() {
	// For documentation, show the pattern
	os.Setenv("PORT", "8080")
	os.Setenv("ENVIRONMENT", "production")

	mux := http.NewServeMux()

	// Health check endpoint
	mux.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusOK)
		w.Write([]byte(`{"status":"healthy","timestamp":"2024-01-01T00:00:00Z"}`))
	})

	// API endpoints
	mux.HandleFunc("/api/", func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusOK)
		w.Write([]byte(`{"message":"API endpoint"}`))
	})

	fmt.Println("Health check available at /health")
	fmt.Println("API available at /api/")
	fmt.Println("Server ready to accept requests")

	// In production:
	// if err := server.Run(context.Background(), mux); err != nil {
	//     log.Fatal(err)
	// }

}
Output:
Health check available at /health
API available at /api/
Server ready to accept requests
Example (WithContext)

ExampleRun_withContext shows context-based cancellation for graceful shutdown.

package main

import (
	"context"
	"fmt"
	"io"
	"log/slog"
	"net/http"
	"os"
	"time"

	"github.com/harrydayexe/GoWebUtilities/server"
)

func main() {
	// Suppress log output for example
	slog.SetDefault(slog.New(slog.NewTextHandler(io.Discard, nil)))

	os.Setenv("PORT", "0") // Use any available port
	os.Setenv("ENVIRONMENT", "test")

	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
	})

	// Create cancellable context
	ctx, cancel := context.WithCancel(context.Background())

	// Run server in background
	done := make(chan error, 1)
	go func() {
		done <- server.Run(ctx, handler)
	}()

	// Simulate doing work
	time.Sleep(100 * time.Millisecond)

	// Cancel context to trigger graceful shutdown
	cancel()

	// Wait for server to shut down
	err := <-done
	if err != nil {
		fmt.Printf("Error: %v\n", err)
	} else {
		fmt.Println("Server shut down gracefully")
	}
}

Types

This section is empty.

Jump to

Keyboard shortcuts

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