114 lines
2.7 KiB
Go
114 lines
2.7 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"net/http"
|
|
"os/signal"
|
|
"syscall"
|
|
"time"
|
|
|
|
"github.com/jackc/pgx/v5"
|
|
|
|
stringunpack "git.grachevko.ru/grachevko/h/string-unpack"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/prometheus/client_golang/prometheus"
|
|
collector "github.com/prometheus/client_golang/prometheus/collectors/version"
|
|
"github.com/prometheus/client_golang/prometheus/promhttp"
|
|
"go.uber.org/zap"
|
|
"golang.org/x/sync/errgroup"
|
|
)
|
|
|
|
func main() {
|
|
logger, _ := zap.NewProduction()
|
|
defer func(logger *zap.Logger) {
|
|
_ = logger.Sync()
|
|
}(logger) // flushes buffer, if any
|
|
|
|
cfg := Config{}
|
|
if err := cfg.Parse(); err != nil {
|
|
logger.Fatal("config parse", zap.Error(err))
|
|
}
|
|
|
|
ctx := context.Background()
|
|
|
|
ctx, stop := signal.NotifyContext(ctx, syscall.SIGINT, syscall.SIGTERM)
|
|
defer stop()
|
|
|
|
var metricServer *http.Server
|
|
{ // Metrics
|
|
prometheus.MustRegister(collector.NewCollector("unpack"))
|
|
mux := http.NewServeMux()
|
|
mux.Handle("/metrics", promhttp.Handler())
|
|
metricServer = &http.Server{
|
|
Handler: mux,
|
|
Addr: ":8089",
|
|
}
|
|
|
|
go func() {
|
|
if err := metricServer.ListenAndServe(); err != nil {
|
|
logger.Error("metric server failed", zap.Error(err))
|
|
}
|
|
}()
|
|
} // Metrics
|
|
|
|
pgconn:
|
|
conn, err := pgx.Connect(ctx, cfg.DSN)
|
|
if err != nil {
|
|
logger.Error("pgx", zap.Error(err))
|
|
|
|
logger.Info("Wait before reconnect", zap.Duration("after", cfg.ReconnectTimeout))
|
|
<-time.After(cfg.ReconnectTimeout)
|
|
logger.Info("Retrying connection")
|
|
goto pgconn
|
|
}
|
|
defer func(conn *pgx.Conn, ctx context.Context) {
|
|
if err = conn.Close(ctx); err != nil {
|
|
logger.Error("pgx close", zap.Error(err))
|
|
}
|
|
}(conn, ctx)
|
|
|
|
var httpServer *http.Server
|
|
{ // Http
|
|
r := gin.Default()
|
|
|
|
stringunpack.Setup(ctx, logger, r.Group("unpack"), conn)
|
|
|
|
httpServer = &http.Server{
|
|
Addr: ":8080",
|
|
Handler: r,
|
|
}
|
|
|
|
go func() {
|
|
if err := httpServer.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
|
|
logger.Error("http server failed", zap.Error(err))
|
|
}
|
|
}()
|
|
} // Http
|
|
|
|
// Listen for the interrupt signal.
|
|
<-ctx.Done()
|
|
|
|
{ // Graceful shutdown
|
|
// Restore default behavior on the interrupt signal and notify user of shutdown.
|
|
stop()
|
|
logger.Info("shutting down gracefully, press Ctrl+C again to force")
|
|
|
|
// The context is used to inform the server it has 5 seconds to finish
|
|
// the request it is currently handling
|
|
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
|
|
defer cancel()
|
|
|
|
g, ctx := errgroup.WithContext(ctx)
|
|
g.Go(func() error { return metricServer.Shutdown(ctx) })
|
|
g.Go(func() error { return httpServer.Shutdown(ctx) })
|
|
|
|
if err := g.Wait(); err != nil {
|
|
logger.Error("graceful shutdown failed", zap.Error(err))
|
|
}
|
|
} // Graceful shutdown
|
|
|
|
logger.Info("Server exiting")
|
|
}
|