Recipe - gRPC + HTTP Hybrid Service
Run Kern HTTP alongside a gRPC server with health checks, reflection, and shared structured logging.
gRPC + HTTP Hybrid Service
Run a Kern HTTP API and a gRPC server side-by-side, sharing the same structured logger and lifecycle.
Setup
import (
"log/slog"
"os"
"time"
"github.com/mobentum/kern"
"github.com/mobentum/kern/extensions/xgrpc"
"github.com/mobentum/kern/extensions/xlog"
"google.golang.org/grpc/health/grpc_health_v1"
)Shared logger
func main() {
logger := xlog.NewLogger(xlog.Config{
Format: "json",
Level: slog.LevelInfo,
})
slog.SetDefault(logger)gRPC server with health and reflection
grpcServer := xgrpc.New(xgrpc.Config{
Addr: ":9090",
Logger: logger,
EnableHealth: true,
EnableReflection: true,
ShutdownTimeout: 10 * time.Second,
UnaryInterceptors: []grpc.UnaryServerInterceptor{
// custom interceptors can be added here
},
}, xgrpc.Registration{
Name: "UserService",
Register: func(s grpc.ServiceRegistrar) {
// pb.RegisterUserServiceServer(s, &userServer{})
},
})
go func() {
slog.Info("gRPC starting", "addr", ":9090")
if err := grpcServer.Run(); err != nil {
slog.Error("gRPC server error", "error", err)
}
}()Kern HTTP server
app := kern.New(
kern.WithRecovery(),
kern.WithSlogLogger(logger),
kern.WithLogger(),
)
app.GET("/health", func(c *kern.Context) {
healthy := grpcServer.HealthService() != nil
c.JSON(200, map[string]interface{}{
"http": "ok",
"grpc": healthy,
})
})
app.GET("/api/users", func(c *kern.Context) {
c.JSON(200, map[string]string{"service": "users"})
})Coordinated shutdown
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
defer stop()
go func() {
<-ctx.Done()
slog.Info("shutting down")
shutdownCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
if err := grpcServer.Shutdown(shutdownCtx); err != nil {
slog.Error("gRPC shutdown error", "error", err)
}
}()
slog.Info("HTTP starting", "addr", ":8080")
if err := app.Run(":8080",
kern.WithGracefulShutdown(10*time.Second),
); err != nil {
slog.Error("HTTP server error", "error", err)
}
}Key patterns
- Shared logger: Both servers use the same
xlogstructured logger - Coordinated lifecycle: gRPC starts first, both shut down gracefully on signal
- Health endpoint: HTTP health check reflects gRPC server health status
- Independent ports: HTTP on
:8080, gRPC on:9090— no port conflict
Recipe - Distributed Tracing with Structured Logging
Propagate trace and span IDs across HTTP requests using custom middleware, xlog structured logging, and slog correlation.
Recipe - Observability Patterns
Practical observability patterns for Kern apps, including request guard deny tracking and session rejection signals.