refactor: commands
ci/woodpecker/push/govulncheck Pipeline was successful Details
ci/woodpecker/push/test Pipeline was successful Details

This commit is contained in:
Dawid Wysokiński 2024-03-15 07:26:11 +01:00
parent 3a903741f5
commit 5b68c58797
Signed by: Kichiyaki
GPG Key ID: B5445E357FB8B892
7 changed files with 84 additions and 107 deletions

View File

@ -4,6 +4,7 @@ import (
"context"
"database/sql"
"fmt"
"log/slog"
"runtime"
"time"
@ -78,11 +79,16 @@ type bundDBConfig struct {
writeTimeout time.Duration
}
const dbPingTimeout = 10 * time.Second
func newBunDB(cfg bundDBConfig) (*bun.DB, error) {
db := bun.NewDB(newSQLDB(cfg), pgdialect.New())
if err := pingDB(db); err != nil {
return nil, err
ctx, cancel := context.WithTimeout(context.Background(), dbPingTimeout)
defer cancel()
if err := db.PingContext(ctx); err != nil {
return nil, fmt.Errorf("couldn't ping db: %w", err)
}
return db, nil
@ -100,15 +106,11 @@ func newSQLDB(cfg bundDBConfig) *sql.DB {
return db
}
const dbPingTimeout = 10 * time.Second
func pingDB(db *bun.DB) error {
ctx, cancel := context.WithTimeout(context.Background(), dbPingTimeout)
defer cancel()
if err := db.PingContext(ctx); err != nil {
return fmt.Errorf("couldn't ping db: %w", err)
func closeBunDB(db *bun.DB, logger *slog.Logger) {
logger.Debug("closing db connections...", slog.Int("db.openConnections", db.Stats().OpenConnections))
if dbCloseErr := db.Close(); dbCloseErr != nil {
logger.Warn("couldn't close db connections", slog.Any("error", dbCloseErr))
} else {
logger.Debug("db connections closed")
}
return nil
}

View File

@ -342,22 +342,12 @@ func runConsumer(c *cli.Context, name string, registerHandlers registerConsumerH
if err != nil {
return err
}
defer func() {
logger.Debug("closing db connections...", slog.Int("db.openConnections", bunDB.Stats().OpenConnections))
if dbCloseErr := bunDB.Close(); dbCloseErr != nil {
logger.Warn("couldn't close db connections", slog.Any("error", dbCloseErr))
} else {
logger.Debug("db connections closed")
}
}()
defer closeBunDB(bunDB, logger)
healthObserver := healthfile.LiveObserver(health.New(), "/tmp/live")
defer func() {
logger.Debug("closing health observer...")
if closeErr := healthObserver.Close(); closeErr != nil {
logger.Warn("couldn't close health observer", slog.Any("error", closeErr))
} else {
logger.Debug("health observer closed")
}
}()

View File

@ -1,6 +1,7 @@
package main
import (
"context"
"fmt"
"log/slog"
"strings"
@ -48,14 +49,7 @@ var cmdDB = &cli.Command{
if err != nil {
return err
}
defer func() {
logger.Debug("closing db connections...", slog.Int("db.openConnections", bunDB.Stats().OpenConnections))
if dbCloseErr := bunDB.Close(); dbCloseErr != nil {
logger.Warn("couldn't close db connections", slog.Any("error", dbCloseErr))
} else {
logger.Debug("db connections closed")
}
}()
defer closeBunDB(bunDB, logger)
migrator := migrations.NewMigrator(bunDB)
@ -63,19 +57,13 @@ var cmdDB = &cli.Command{
return fmt.Errorf("couldn't init migrator: %w", err)
}
// we use c.Context instead of shutdownSignalCtx here because we still want to unlock the db
// even after one of the shutdown signals has been received
defer unlockMigrations(c.Context, migrator, logger)
if err = migrator.Lock(shutdownSignalCtx); err != nil {
return fmt.Errorf("couldn't lock db: %w", err)
}
defer func() {
logger.Debug("unlocking db...")
// we use c.Context instead of shutdownSignalCtx here because we still want to unlock the db
// even after one of the shutdown signals has been received
if unlockErr := migrator.Unlock(c.Context); unlockErr != nil {
logger.Warn("couldn't unlock db", slog.Any("error", unlockErr))
} else {
logger.Debug("db unlocked")
}
}()
group, err := migrator.Migrate(shutdownSignalCtx)
if err != nil {
@ -110,30 +98,17 @@ var cmdDB = &cli.Command{
if err != nil {
return err
}
defer func() {
logger.Debug("closing db connections...", slog.Int("db.openConnections", bunDB.Stats().OpenConnections))
if dbCloseErr := bunDB.Close(); dbCloseErr != nil {
logger.Warn("couldn't close db connections", slog.Any("error", dbCloseErr))
} else {
logger.Debug("db connections closed")
}
}()
defer closeBunDB(bunDB, logger)
migrator := migrations.NewMigrator(bunDB)
// we use c.Context instead of shutdownSignalCtx here because we still want to unlock the db
// even after one of the shutdown signals has been received
defer unlockMigrations(c.Context, migrator, logger)
if err = migrator.Lock(shutdownSignalCtx); err != nil {
return fmt.Errorf("couldn't lock db: %w", err)
}
defer func() {
logger.Debug("unlocking db...")
// we use c.Context instead of shutdownSignalCtx here because we still want to unlock the db
// even after one of the shutdown signals has been received
if unlockErr := migrator.Unlock(c.Context); unlockErr != nil {
logger.Warn("couldn't unlock db", slog.Any("error", unlockErr))
} else {
logger.Debug("db unlocked")
}
}()
group, err := migrator.Rollback(shutdownSignalCtx)
if err != nil {
@ -212,3 +187,12 @@ var cmdDB = &cli.Command{
},
},
}
func unlockMigrations(ctx context.Context, migrator *migrate.Migrator, logger *slog.Logger) {
logger.Debug("unlocking db...")
if unlockErr := migrator.Unlock(ctx); unlockErr != nil {
logger.Warn("couldn't unlock db", slog.Any("error", unlockErr))
} else {
logger.Debug("db unlocked")
}
}

View File

@ -51,14 +51,7 @@ var (
if err != nil {
return err
}
defer func() {
logger.Debug("closing db connections...", slog.Int("db.openConnections", bunDB.Stats().OpenConnections))
if dbCloseErr := bunDB.Close(); dbCloseErr != nil {
logger.Warn("couldn't close db connections", slog.Any("error", dbCloseErr))
} else {
logger.Debug("db connections closed")
}
}()
defer closeBunDB(bunDB, logger)
serverPublisher := adapter.NewServerWatermillPublisher(
publisher,
@ -114,14 +107,7 @@ var (
if err != nil {
return err
}
defer func() {
logger.Debug("closing db connections...", slog.Int("db.openConnections", bunDB.Stats().OpenConnections))
if dbCloseErr := bunDB.Close(); dbCloseErr != nil {
logger.Warn("couldn't close db connections", slog.Any("error", dbCloseErr))
} else {
logger.Debug("db connections closed")
}
}()
defer closeBunDB(bunDB, logger)
ennoblementPublisher := adapter.NewEnnoblementWatermillPublisher(
publisher,
@ -183,14 +169,7 @@ var (
if err != nil {
return err
}
defer func() {
logger.Debug("closing db connections...", slog.Int("db.openConnections", bunDB.Stats().OpenConnections))
if dbCloseErr := bunDB.Close(); dbCloseErr != nil {
logger.Warn("couldn't close db connections", slog.Any("error", dbCloseErr))
} else {
logger.Debug("db connections closed")
}
}()
defer closeBunDB(bunDB, logger)
tribeSnapshotPublisher := adapter.NewSnapshotWatermillPublisher(
publisher,

View File

@ -8,9 +8,9 @@ import (
"net/http"
"net/url"
"slices"
"strings"
"time"
"gitea.dwysokinski.me/Kichiyaki/chiclientip"
"gitea.dwysokinski.me/twhelp/corev3/internal/adapter"
"gitea.dwysokinski.me/twhelp/corev3/internal/app"
"gitea.dwysokinski.me/twhelp/corev3/internal/chislog"
@ -18,6 +18,7 @@ import (
"gitea.dwysokinski.me/twhelp/corev3/internal/port"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
"github.com/realclientip/realclientip-go"
"github.com/urfave/cli/v2"
)
@ -27,6 +28,12 @@ var (
EnvVars: []string{"API_PORT"},
Value: 9234, //nolint:gomnd
}
apiServerHandlerTimeoutFlag = &cli.DurationFlag{
Name: "api.handlerTimeout",
EnvVars: []string{"API_HANDLER_TIMEOUT"},
Value: 5 * time.Second, //nolint:gomnd,
Usage: "https://pkg.go.dev/net/http#TimeoutHandler",
}
apiServerReadTimeoutFlag = &cli.DurationFlag{
Name: "api.readTimeout",
EnvVars: []string{"API_READ_TIMEOUT"},
@ -68,6 +75,7 @@ var (
}
apiServerFlags = []cli.Flag{
apiServerPortFlag,
apiServerHandlerTimeoutFlag,
apiServerReadTimeoutFlag,
apiServerReadHeaderTimeoutFlag,
apiServerWriteTimeoutFlag,
@ -95,14 +103,7 @@ var cmdServe = &cli.Command{
if err != nil {
return err
}
defer func() {
logger.Debug("closing db connections...", slog.Int("db.openConnections", bunDB.Stats().OpenConnections))
if dbCloseErr := bunDB.Close(); dbCloseErr != nil {
logger.Warn("couldn't close db connections", slog.Any("error", dbCloseErr))
} else {
logger.Debug("db connections closed")
}
}()
defer closeBunDB(bunDB, logger)
// adapters
versionRepo := adapter.NewVersionBunRepository(bunDB)
@ -139,20 +140,25 @@ var cmdServe = &cli.Command{
return oapiCfgErr
}
r.Use(newAPIMiddlewares(logger)...)
r.Group(func(r chi.Router) {
r.Use(middleware.Recoverer)
r.Mount(metaBasePath, port.NewMetaHTTPHandler(h))
})
r.Mount(metaBasePath, port.NewMetaHTTPHandler(h))
r.Group(func(r chi.Router) {
r.Use(newAPIMiddlewares(c, logger)...)
r.Mount(apiBasePath, port.NewAPIHTTPHandler(
versionSvc,
serverSvc,
tribeSvc,
playerSvc,
villageSvc,
ennoblementSvc,
tribeChangeSvc,
port.WithOpenAPIConfig(oapiCfg),
))
r.Mount(apiBasePath, port.NewAPIHTTPHandler(
versionSvc,
serverSvc,
tribeSvc,
playerSvc,
villageSvc,
ennoblementSvc,
tribeChangeSvc,
port.WithOpenAPIConfig(oapiCfg),
))
})
return nil
},
@ -213,11 +219,21 @@ func newOpenAPIConfigFromFlags(c *cli.Context) (port.OpenAPIConfig, error) {
}, nil
}
func newAPIMiddlewares(logger *slog.Logger) chi.Middlewares {
func newAPIMiddlewares(c *cli.Context, logger *slog.Logger) chi.Middlewares {
return chi.Middlewares{
chislog.Logger(logger, chislog.WithFilter(func(r *http.Request) bool {
return !strings.HasPrefix(r.URL.Path, metaBasePath)
chiclientip.ClientIP(
realclientip.NewChainStrategy(
realclientip.Must(realclientip.NewRightmostNonPrivateStrategy("X-Forwarded-For")),
realclientip.RemoteAddrStrategy{},
),
),
chislog.Logger(logger, chislog.WithIPExtractor(func(r *http.Request) string {
clientIP, _ := chiclientip.ClientIPFromContext(r.Context())
return clientIP
})),
middleware.Recoverer,
func(next http.Handler) http.Handler {
return http.TimeoutHandler(next, c.Duration(apiServerHandlerTimeoutFlag.Name), "Timeout")
},
}
}

2
go.mod
View File

@ -3,6 +3,7 @@ module gitea.dwysokinski.me/twhelp/corev3
go 1.22
require (
gitea.dwysokinski.me/Kichiyaki/chiclientip v0.1.0
github.com/ThreeDotsLabs/watermill v1.3.5
github.com/ThreeDotsLabs/watermill-amqp/v2 v2.1.1
github.com/brianvoe/gofakeit/v7 v7.0.2
@ -16,6 +17,7 @@ require (
github.com/google/uuid v1.6.0
github.com/oapi-codegen/runtime v1.1.1
github.com/ory/dockertest/v3 v3.10.0
github.com/realclientip/realclientip-go v1.0.0
github.com/stretchr/testify v1.9.0
github.com/uptrace/bun v1.1.17
github.com/uptrace/bun/dbfixture v1.1.17

4
go.sum
View File

@ -1,3 +1,5 @@
gitea.dwysokinski.me/Kichiyaki/chiclientip v0.1.0 h1:5e5Uh+Am1PBSW1cYsbAuEhrGSZHxP7JfNeNa+FXbQ/4=
gitea.dwysokinski.me/Kichiyaki/chiclientip v0.1.0/go.mod h1:zMTruKo30+qM3dG4yhAPOxK/5hUEBhKiDSrV0VRlZnI=
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8=
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
@ -155,6 +157,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rabbitmq/amqp091-go v1.9.0 h1:qrQtyzB4H8BQgEuJwhmVQqVHB9O4+MNDJCCAcpc3Aoo=
github.com/rabbitmq/amqp091-go v1.9.0/go.mod h1:+jPrT9iY2eLjRaMSRHUhc3z14E/l85kv/f+6luSD3pc=
github.com/realclientip/realclientip-go v1.0.0 h1:+yPxeC0mEaJzq1BfCt2h4BxlyrvIIBzR6suDc3BEF1U=
github.com/realclientip/realclientip-go v1.0.0/go.mod h1:CXnUdVwFRcXFJIRb/dTYqbT7ud48+Pi2pFm80bxDmcI=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=