This document covers the Echo HTTP server implementation, middleware stack, route registration patterns, graceful shutdown mechanisms, and overall server lifecycle management. For information about the specific API services exposed by the server, see API and Service Architecture. For deployment configuration, see Docker and Container Deployment.
The memos server is built on Echo v5, a high-performance HTTP framework for Go. The server handles all HTTP traffic through a single unified HTTP server instance, with gRPC services exposed via gRPC-Gateway HTTP/JSON endpoints rather than as separate gRPC servers. This design simplifies deployment and allows the application to be distributed as a single binary.
Key Design Decisions:
The server is represented by the Server struct which encapsulates all components needed to run the application.
Server Components:
| Component | Type | Purpose |
|---|---|---|
echoServer | *echo.Echo | Core HTTP router and middleware handler |
httpServer | *http.Server | Standard library HTTP server wrapping Echo |
Store | *store.Store | Database abstraction layer |
Profile | *profile.Profile | Application configuration (port, mode, paths) |
Secret | string | JWT signing key for authentication |
runnerCancelFuncs | []context.CancelFunc | Cleanup functions for background tasks |
Sources: server/server.go27-35
The NewServer function performs all initialization steps required before the server can accept requests.
Initialization Steps:
/healthz endpoint (server/server.go58-61)Sources: server/server.go37-83
The server uses Echo's middleware system for cross-cutting concerns. Currently, a minimal middleware stack is employed.
Registered Middleware:
| Middleware | Purpose | Registration |
|---|---|---|
middleware.Recover() | Catches panics and returns 500 errors | server/server.go44 |
Note: Additional middleware such as logging, CORS, and authentication are handled at the service layer rather than globally. The gRPC interceptor pattern is used for request-level concerns in API handlers.
Sources: server/server.go44
The order of route registration is critical for proper request handling. Routes are registered from most specific to least specific to ensure correct matching.
Registration Order Rationale:
/healthz): Simple endpoint for load balancer health checks/o/r/*): Critical positioning - registered before gRPC gateway to handle Safari range requests properly using native HTTP serving/explore/rss.xml): Specialized feed generation endpoints/api/v1/*): Catch-all for all API endpointsWhy File Server is Registered Before Gateway:
Safari's video player issues range requests (Range: bytes=0-1) to video files. If the gRPC gateway handles these requests, it doesn't properly support range requests, causing playback failures. By registering the file server routes first, video/audio files are served using http.ServeContent which handles range requests correctly.
Sources: server/server.go58-80
The server follows a well-defined lifecycle from startup through graceful shutdown.
The Start method configures the network listener and begins accepting connections.
Listener Configuration:
The server supports two network modes:
| Mode | Configuration | Listener Address |
|---|---|---|
| TCP | Default | {addr}:{port} (e.g., localhost:8080) |
| Unix Socket | MEMOS_UNIX_SOCK set | Unix domain socket path |
Sources: server/server.go85-109
The Shutdown method ensures all resources are properly cleaned up before process termination.
Shutdown Sequence:
Timeout Behavior: If shutdown doesn't complete within 10 seconds, the context is cancelled and remaining operations are forcefully terminated.
Sources: server/server.go111-137
The server manages long-running background tasks using goroutines and context cancellation.
The S3 presign runner periodically regenerates presigned URLs for S3-stored resources.
Runner Characteristics:
| Aspect | Implementation |
|---|---|
| Purpose | Regenerate expiring S3 presigned URLs |
| Initialization | Runs once immediately at startup |
| Schedule | Continuous loop with sleep intervals |
| Cancellation | Context-based via s3Cancel() |
| Location | server/runner/s3presign/ |
Runner Lifecycle:
Cancellation Pattern: Each runner gets its own child context that can be cancelled independently. The cancel function is stored in runnerCancelFuncs so it can be called during shutdown.
Sources: server/server.go139-159
Server configuration is managed through the profile.Profile struct, typically populated from environment variables.
Key Configuration Fields:
| Field | Type | Environment Variable | Default | Purpose |
|---|---|---|---|---|
Addr | string | MEMOS_ADDR | localhost | Bind address |
Port | int | MEMOS_PORT | 8080 | HTTP port |
UNIXSock | string | MEMOS_UNIX_SOCK | - | Unix socket path |
Mode | string | MEMOS_MODE | dev | Runtime mode |
Demo | bool | MEMOS_DEMO | false | Demo mode flag |
Data | string | MEMOS_DATA | ./data | Data directory |
Server Modes:
dev): Verbose logging, debug features enabledprod): Optimized logging, debug features disabled"usememos", disables certain featuresSources: server/server.go28-30 internal/profile/
The following diagram shows the complete path of an HTTP request through the server infrastructure.
Request Processing Steps:
net.Listener accepts TCP or Unix socket connectionshttp.Server handles HTTP protocol parsingServeHTTP processes the requestSources: server/server.go85-109
The server implements multiple layers of error handling to ensure robustness.
Error Handling Layers:
middleware.Recover() catches panics and returns 500 errorsGraceful Degradation: If a background runner fails, it logs the error but doesn't crash the server. The S3 presign runner will log errors and continue on its next iteration.
Sources: server/server.go44 server/server.go111-137
The memos server infrastructure provides a robust, production-ready HTTP server with these key characteristics:
The server design prioritizes simplicity and reliability, making it suitable for self-hosted deployments ranging from personal instances to larger team installations.