Implement health check for deploy. Make version endpoint to return revision if not set
This commit is contained in:
@@ -7,11 +7,6 @@ Server.Tls.Enabled = false
|
|||||||
Server.Tls.CertFile =
|
Server.Tls.CertFile =
|
||||||
Server.Tls.KeyFile =
|
Server.Tls.KeyFile =
|
||||||
|
|
||||||
Socket.MaxHttpBufferSize = 2097152
|
|
||||||
Socket.PingInterval = 25s
|
|
||||||
Socket.PingTimeout = 20s
|
|
||||||
Socket.Debug = false
|
|
||||||
|
|
||||||
# Prometheus settings
|
# Prometheus settings
|
||||||
Metrics.Endpoint = /metrics
|
Metrics.Endpoint = /metrics
|
||||||
Metrics.HistogramBuckets = 0.001,0.002,0.005,0.01,0.025,0.05,0.1,0.25,0.5,1,2.5,5,10
|
Metrics.HistogramBuckets = 0.001,0.002,0.005,0.01,0.025,0.05,0.1,0.25,0.5,1,2.5,5,10
|
||||||
@@ -64,4 +59,4 @@ YooKassa.ApiBaseSecret =
|
|||||||
YooKassa.ApiPaymentKey =
|
YooKassa.ApiPaymentKey =
|
||||||
YooKassa.ApiPaymentSecret =
|
YooKassa.ApiPaymentSecret =
|
||||||
# Timeout to process yookassa callback
|
# Timeout to process yookassa callback
|
||||||
YooKassa.CallbackProcessTimeout = 1s
|
YooKassa.CallbackProcessTimeout = 1s
|
||||||
|
|||||||
46
internal/api/health/health_handler.go
Normal file
46
internal/api/health/health_handler.go
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
package health
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"payouts/internal/service/database"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Route health route
|
||||||
|
const Route = "/health"
|
||||||
|
|
||||||
|
// New constructs a new health Handler.
|
||||||
|
func New(dbService database.Service) (Handler, error) {
|
||||||
|
return &handler{
|
||||||
|
dbService: dbService,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type handler struct {
|
||||||
|
dbService database.Service
|
||||||
|
}
|
||||||
|
|
||||||
|
// HealthHandler handles the health check requests
|
||||||
|
func (h *handler) Health(w http.ResponseWriter, r *http.Request) {
|
||||||
|
defer r.Body.Close()
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
|
||||||
|
status := map[string]any{}
|
||||||
|
|
||||||
|
// Check database connection
|
||||||
|
err := h.dbService.HealthCheck()
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(http.StatusServiceUnavailable)
|
||||||
|
status["Error"] = fmt.Sprintf("%v", err)
|
||||||
|
slog.Error("Health check failed", slog.String("error", status["Error"].(string)))
|
||||||
|
} else {
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
}
|
||||||
|
status["OK"] = (err == nil)
|
||||||
|
|
||||||
|
encoder := json.NewEncoder(w)
|
||||||
|
encoder.Encode(status)
|
||||||
|
}
|
||||||
16
internal/api/health/module.go
Normal file
16
internal/api/health/module.go
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
package health
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"go.uber.org/fx"
|
||||||
|
)
|
||||||
|
|
||||||
|
var Module = fx.Options(
|
||||||
|
fx.Provide(New),
|
||||||
|
)
|
||||||
|
|
||||||
|
// Handler health handler interface
|
||||||
|
type Handler interface {
|
||||||
|
Health(http.ResponseWriter, *http.Request)
|
||||||
|
}
|
||||||
@@ -11,6 +11,7 @@ import (
|
|||||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||||
"go.uber.org/fx"
|
"go.uber.org/fx"
|
||||||
|
|
||||||
|
"payouts/internal/api/health"
|
||||||
"payouts/internal/api/payout"
|
"payouts/internal/api/payout"
|
||||||
"payouts/internal/api/user"
|
"payouts/internal/api/user"
|
||||||
"payouts/internal/api/version"
|
"payouts/internal/api/version"
|
||||||
@@ -21,6 +22,7 @@ import (
|
|||||||
// Module is a fx module
|
// Module is a fx module
|
||||||
var Module = fx.Options(
|
var Module = fx.Options(
|
||||||
user.Module,
|
user.Module,
|
||||||
|
health.Module,
|
||||||
payout.Module,
|
payout.Module,
|
||||||
version.Module,
|
version.Module,
|
||||||
monitoring.Module,
|
monitoring.Module,
|
||||||
@@ -40,6 +42,7 @@ type Params struct {
|
|||||||
PayoutHandler payout.Handler
|
PayoutHandler payout.Handler
|
||||||
UserHandler user.Handler
|
UserHandler user.Handler
|
||||||
Version version.Handler
|
Version version.Handler
|
||||||
|
HealthHandler health.Handler
|
||||||
|
|
||||||
Metrics monitoring.Metrics
|
Metrics monitoring.Metrics
|
||||||
}
|
}
|
||||||
@@ -50,7 +53,10 @@ func RegisterRoutes(p Params, lc fx.Lifecycle) {
|
|||||||
router := mux.NewRouter()
|
router := mux.NewRouter()
|
||||||
router.StrictSlash(true)
|
router.StrictSlash(true)
|
||||||
|
|
||||||
|
// Version endpoint
|
||||||
router.HandleFunc(version.Route, p.Version.VersionHandler).Methods(http.MethodGet)
|
router.HandleFunc(version.Route, p.Version.VersionHandler).Methods(http.MethodGet)
|
||||||
|
// Health check endpoint
|
||||||
|
router.HandleFunc(health.Route, p.HealthHandler.Health).Methods(http.MethodGet)
|
||||||
|
|
||||||
if p.AppConfig.Server.EnablePProfEndpoints {
|
if p.AppConfig.Server.EnablePProfEndpoints {
|
||||||
router.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
|
router.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package version
|
|||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"runtime/debug"
|
||||||
|
|
||||||
"go.uber.org/fx"
|
"go.uber.org/fx"
|
||||||
|
|
||||||
@@ -39,7 +40,20 @@ type handler struct {
|
|||||||
func (h *handler) VersionHandler(w http.ResponseWriter, r *http.Request) {
|
func (h *handler) VersionHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
defer r.Body.Close()
|
defer r.Body.Close()
|
||||||
|
|
||||||
|
ver := h.version
|
||||||
|
if ver == "unknown" {
|
||||||
|
buildInfo, ok := debug.ReadBuildInfo()
|
||||||
|
if ok {
|
||||||
|
for _, setting := range buildInfo.Settings {
|
||||||
|
if setting.Key == "vcs.revision" {
|
||||||
|
ver = ver + "-" + setting.Value
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "text/plain")
|
w.Header().Set("Content-Type", "text/plain")
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
io.WriteString(w, h.version)
|
io.WriteString(w, ver+"\n")
|
||||||
}
|
}
|
||||||
@@ -109,3 +109,17 @@ func (d *dbService) UpdatePayoutByPayoutID(payoutId string, updateModel orm.Payo
|
|||||||
p := d.getParams(opts...)
|
p := d.getParams(opts...)
|
||||||
return gorm.G[orm.Payout](d.db).Where("payout_id = ?", payoutId).Updates(p.ctx, updateModel)
|
return gorm.G[orm.Payout](d.db).Where("payout_id = ?", payoutId).Updates(p.ctx, updateModel)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HealthCheck implements [Service].
|
||||||
|
func (d *dbService) HealthCheck() error {
|
||||||
|
if d.db == nil {
|
||||||
|
return errors.New("database connection is nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
db, err := d.db.DB()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return db.Ping()
|
||||||
|
}
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ type Service interface {
|
|||||||
CreatePayout(payoutModel *orm.Payout, opts ...Optional) error
|
CreatePayout(payoutModel *orm.Payout, opts ...Optional) error
|
||||||
UpdatePayoutById(id uint, updateModel orm.Payout, opts ...Optional) (int, error)
|
UpdatePayoutById(id uint, updateModel orm.Payout, opts ...Optional) (int, error)
|
||||||
UpdatePayoutByPayoutID(payoutId string, updateModel orm.Payout, opts ...Optional) (int, error)
|
UpdatePayoutByPayoutID(payoutId string, updateModel orm.Payout, opts ...Optional) (int, error)
|
||||||
|
HealthCheck() error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Params represents the module input params
|
// Params represents the module input params
|
||||||
|
|||||||
@@ -1,10 +1,3 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) New Cloud Technologies, Ltd., 2013-2026
|
|
||||||
*
|
|
||||||
* You can not use the contents of the file in any way without New Cloud Technologies Ltd. written permission.
|
|
||||||
* To obtain such a permit, you should contact New Cloud Technologies, Ltd. at https://myoffice.ru/contacts/
|
|
||||||
*/
|
|
||||||
|
|
||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
unknown
|
unknown
|
||||||
Reference in New Issue
Block a user