From e822a5b11e24652d0ef17638495977085f09670f Mon Sep 17 00:00:00 2001 From: sxwebdev Date: Tue, 17 Mar 2026 13:34:47 +0300 Subject: [PATCH] full refactor service --- .golangci.yml | 83 -------- README.md | 56 ++---- cfg/cfg.go | 169 ---------------- cfg/gen_flags.go | 42 ---- cfg/genyaml.go | 52 ----- cfg/help.go | 71 ------- cfg/loader.go | 38 ---- cfg/markdown.go | 147 -------------- cfg/options.go | 78 -------- cfg/tests.go | 57 ------ cfg/types.go | 13 -- cfg/validate.go | 124 ------------ cfg/yamlloader/loader.go | 40 ---- clients/connectrpc_client/go.mod | 10 +- clients/connectrpc_client/go.sum | 12 +- clients/grpc_client/go.mod | 14 +- clients/grpc_client/go.sum | 56 +++--- go.mod | 42 ++-- go.sum | 96 ++++----- launcher/launcher.go | 33 +++- {ops => launcher/ops}/config.go | 0 {ops => launcher/ops}/health.go | 13 +- {ops => launcher/ops}/metrics.go | 0 {ops => launcher/ops}/ops.go | 8 +- {ops => launcher/ops}/profiler.go | 5 + {ops => launcher/ops}/sentry/config.go | 0 {ops => launcher/ops}/sentry/go.mod | 10 +- {ops => launcher/ops}/sentry/go.sum | 16 +- {ops => launcher/ops}/sentry/sentry.go | 0 {ops => launcher/ops}/types.go | 0 launcher/options.go | 2 +- {service => launcher}/service.go | 36 +--- launcher/service_options.go | 179 +++++++++++++++++ .../services}/pingpong/logger.go | 0 .../services}/pingpong/options.go | 0 .../services}/pingpong/ping_pong.go | 4 +- launcher/services_runner.go | 24 +-- launcher/types/types.go | 26 +++ logger/logger.go | 4 +- service/enabler.go | 5 - service/health.go | 14 -- service/options.go | 187 ------------------ testutils/print.go | 14 -- transport/connectrpc_transport/go.mod | 10 +- transport/connectrpc_transport/go.sum | 24 +-- transport/grpc_transport/go.mod | 31 +-- transport/grpc_transport/go.sum | 72 +++---- util/signal/signal.go | 2 +- 48 files changed, 467 insertions(+), 1452 deletions(-) delete mode 100644 .golangci.yml delete mode 100644 cfg/cfg.go delete mode 100644 cfg/gen_flags.go delete mode 100644 cfg/genyaml.go delete mode 100644 cfg/help.go delete mode 100644 cfg/loader.go delete mode 100644 cfg/markdown.go delete mode 100644 cfg/options.go delete mode 100644 cfg/tests.go delete mode 100644 cfg/types.go delete mode 100644 cfg/validate.go delete mode 100644 cfg/yamlloader/loader.go rename {ops => launcher/ops}/config.go (100%) rename {ops => launcher/ops}/health.go (92%) rename {ops => launcher/ops}/metrics.go (100%) rename {ops => launcher/ops}/ops.go (92%) rename {ops => launcher/ops}/profiler.go (86%) rename {ops => launcher/ops}/sentry/config.go (100%) rename {ops => launcher/ops}/sentry/go.mod (50%) rename {ops => launcher/ops}/sentry/go.sum (80%) rename {ops => launcher/ops}/sentry/sentry.go (100%) rename {ops => launcher/ops}/types.go (100%) rename {service => launcher}/service.go (77%) create mode 100644 launcher/service_options.go rename {service => launcher/services}/pingpong/logger.go (100%) rename {service => launcher/services}/pingpong/options.go (100%) rename {service => launcher/services}/pingpong/ping_pong.go (93%) create mode 100644 launcher/types/types.go delete mode 100644 service/enabler.go delete mode 100644 service/health.go delete mode 100644 service/options.go delete mode 100644 testutils/print.go diff --git a/.golangci.yml b/.golangci.yml deleted file mode 100644 index 52470f9..0000000 --- a/.golangci.yml +++ /dev/null @@ -1,83 +0,0 @@ -linters-settings: - tagliatelle: - case: - use-field-name: true - rules: - json: snake - yaml: snake - gocognit: - min-complexity: 80 - funlen: - lines: 190 - statements: -1 - ignore-comments: true - interfacebloat: - max: 20 - gocyclo: - min-complexity: 45 - cyclop: - max-complexity: 25 - lll: - line-length: 170 - tab-width: 2 - -linters: - enable-all: true - - disable: - - tenv - - wsl - - wrapcheck - - varnamelen - - tagalign - - recvcheck - - mnd - - nlreturn - - exhaustruct - - exhaustive - - gochecknoglobals - - err113 - - depguard - - godox - -issues: - exclude-rules: - - path: _test\.go - linters: - - funlen - - misspell - exclude-files: - - ".*\\.sql\\.go" - - ".*\\.pb\\.go" - - ".*\\.connect\\.go" - exclude-dirs: - - bin - - api - - schema - - sql - - internal/templates - - pb - - schema - exclude: - - "missing type in composite literal" - - "var-naming: don't use an underscore in package name" - - "should not use underscores in package names" -run: - modules-download-mode: readonly - allow-parallel-runners: true - timeout: 2m - tests: false - -severity: - default-severity: error - rules: - - severity: warning - linters: - - godox - - severity: info - linters: - - dupl - -output: - show-stats: true - sort-results: true diff --git a/README.md b/README.md index aa46c17..3794702 100644 --- a/README.md +++ b/README.md @@ -13,8 +13,8 @@ A Go microservices framework with runtime launcher and services runner - [x] Launcher - [x] Services - [x] Services runner -- [x] Service `Enabler` interface -- [x] Service `HealthChecker` interface +- [x] `Enabler` interface +- [x] `HealthChecker` interface - [x] Metrics - [x] Health checker - [x] Ping pong service @@ -23,7 +23,6 @@ A Go microservices framework with runtime launcher and services runner - [x] GRPC client - [x] ConnectRPC transport - [x] ConnectRPC client -- [x] Config loader ## How to use @@ -60,12 +59,12 @@ ln := launcher.New( ```go // init -svc := service.New( - service.WithName("test-service"), - service.WithStart(func(_ context.Context) error { +svc := launcher.NewService( + launcher.WithServiceName("test-service"), + launcher.WithStart(func(_ context.Context) error { return nil }), - service.WithStop(func(_ context.Context) error { + launcher.WithStop(func(_ context.Context) error { time.Sleep(time.Second * 3) return nil }), @@ -78,21 +77,21 @@ ln.ServicesRunner().Register(svc) ### Init and register ping pong service ```go +import "github.com/tkcrm/mx/launcher/services/pingpong" + // init -pingPongSvc := service.New(service.WithService(pingpong.New(logger))) +pingPongSvc := launcher.NewService(launcher.WithService(pingpong.New(logger))) // register in launcher ln.ServicesRunner().Register(pingPongSvc) ``` -You can also register any service that implements the following interface +### Register any service that implements IService + +Any struct with `Name()`, `Start()`, and `Stop()` methods satisfies `types.IService` and can be wrapped with `launcher.NewService`: ```go -type IService interface { - Name() string - Start(ctx context.Context) error - Stop(ctx context.Context) error -} +import "github.com/tkcrm/mx/launcher/types" type books struct { name string @@ -119,42 +118,27 @@ func (s books) Start(ctx context.Context) error { func (s books) Stop(ctx context.Context) error { return nil } -var _ service.HealthChecker = (*books)(nil) - -var _ service.IService = (*books)(nil) +var _ types.HealthChecker = (*books)(nil) +var _ types.IService = (*books)(nil) func main() { ln := launcher.New() // register service in launcher with health checker ln.ServicesRunner().Register( - service.New( - service.WithService(New()), + launcher.NewService( + launcher.WithService(New()), ), ) } ``` -### Start launcher and all services with graceful shutdown +### Graceful shutdown + +The first signal (SIGTERM / SIGINT / SIGQUIT) starts a graceful shutdown. A second signal forces immediate exit. ```go if err := ln.Run(); err != nil { logger.Fatal(err) } ``` - -## Config loader - -```go -type Config struct { - ServiceName string `default:"mx-example" validate:"required"` - Prometheus prometheus.Config - Ops ops.Config - Grpc grpc_transport.Config -} - -conf := new(Config) -if err := cfg.Load(conf); err != nil { - logger.Fatalf("could not load configuration: %s", err) -} -``` diff --git a/cfg/cfg.go b/cfg/cfg.go deleted file mode 100644 index 7968b22..0000000 --- a/cfg/cfg.go +++ /dev/null @@ -1,169 +0,0 @@ -package cfg - -import ( - "errors" - "fmt" - "io" - "os" - "path" - "reflect" - "slices" - "strings" - - "github.com/cristalhq/aconfig" - "github.com/cristalhq/aconfig/aconfigdotenv" - "github.com/tkcrm/mx/cfg/yamlloader" - "github.com/tkcrm/mx/util/files" -) - -var ( - boolTrueValues = []string{"true", "1"} - fileDecoders = map[string]aconfig.FileDecoder{ - ".env": aconfigdotenv.New(), - ".yaml": yamlloader.New(), - ".yml": yamlloader.New(), - } -) - -type config struct { - options *options - - out io.Writer - - args []string - exit func(int) -} - -// Load environment variables from `os env`, flags, `.env`, `.yaml` files and pass it to struct. -// -// For local development use `.env` file from root project. -// -// Load also call a `Validate` method if it proided. -// -// Example: -// -// var config internalConfig.Config -// if err := cfg.Load(&config); err != nil { -// logger.Fatalf("could not load configuration: %v", err) -// } -func Load(cfg any, opts ...Option) error { - if reflect.ValueOf(cfg).Kind() != reflect.Ptr { - return errors.New("config must be a pointer") - } - - options := newOptions(opts...) - - c := config{ - out: os.Stdout, - exit: os.Exit, - args: os.Args[1:], - options: options, - } - - aconf, err := getAconfig(c) - if err != nil { - return err - } - - loader := aconfig.LoaderFor(cfg, aconf) - - if err := loader.Load(); err != nil { - return err - } - - if options.validate { - if err := c.validateEnvs(cfg, loader); err != nil { - return err - } - } - - return nil -} - -func (c *config) print(value string) { - _, _ = fmt.Fprintln(c.out, value) -} - -func GetConfigFields(loader *aconfig.Loader) []ConfigField { - res := []ConfigField{} - - loader.WalkFields(func(f aconfig.Field) bool { - newField := ConfigField{ - Path: f.Name(), - DefaultValue: f.Tag("default"), - Usage: f.Tag("usage"), - Example: f.Tag("example"), - ValidateParams: f.Tag("validate"), - } - - if slices.Contains(boolTrueValues, strings.ToLower(f.Tag("required"))) { - newField.IsRequired = true - } - - if slices.Contains(boolTrueValues, strings.ToLower(f.Tag("secret"))) { - newField.IsSecret = true - } - - if slices.Contains(boolTrueValues, strings.ToLower(f.Tag("disable_validation"))) { - newField.DisableValidation = true - } - - if strings.Contains(newField.ValidateParams, "required") { - newField.IsRequired = true - } - - envName := f.Tag("env") - - field := f - var ok bool - for { - if field, ok = field.Parent(); !ok { - break - } - - envName = fmt.Sprintf("%s_%s", field.Tag("env"), envName) - - if !newField.DisableValidation && - slices.Contains( - boolTrueValues, - strings.ToLower(field.Tag("disable_validation")), - ) { - newField.DisableValidation = true - } - } - - newField.EnvName = envName - - res = append(res, newField) - - return true - }) - - return res -} - -// getAconfig return aconfig.Config based on options. -func getAconfig(conf config) (aconfig.Config, error) { - pwdDir, err := os.Getwd() - if err != nil { - return aconfig.Config{}, err - } - - aconf := conf.options.loaderConfig - if aconf.FileDecoders == nil { - aconf.FileDecoders = fileDecoders - } - - for _, file := range aconf.Files { - absFilePath := file - if !path.IsAbs(file) { - absFilePath = path.Join(pwdDir, file) - } - - if !files.ExistsPath(absFilePath) { - return aconfig.Config{}, fmt.Errorf("config file not found: %s", absFilePath) - } - } - - return aconf, nil -} diff --git a/cfg/gen_flags.go b/cfg/gen_flags.go deleted file mode 100644 index 26e9f88..0000000 --- a/cfg/gen_flags.go +++ /dev/null @@ -1,42 +0,0 @@ -package cfg - -import ( - "bytes" - "errors" - "os" - "reflect" - - "github.com/cristalhq/aconfig" -) - -func GenerateFlags(cfg any, opts ...Option) (string, error) { - if reflect.ValueOf(cfg).Kind() != reflect.Ptr { - return "", errors.New("config must be a pointer") - } - - options := newOptions(opts...) - - c := config{ - out: os.Stdout, - exit: os.Exit, - args: os.Args[1:], - options: options, - } - - aconf, err := getAconfig(c) - if err != nil { - return "", err - } - - loader := aconfig.LoaderFor(cfg, aconf) - - if err := loader.Load(); err != nil { - return "", err - } - - buf := &bytes.Buffer{} - loader.Flags().SetOutput(buf) - loader.Flags().PrintDefaults() - - return buf.String(), nil -} diff --git a/cfg/genyaml.go b/cfg/genyaml.go deleted file mode 100644 index 7e3c691..0000000 --- a/cfg/genyaml.go +++ /dev/null @@ -1,52 +0,0 @@ -package cfg - -import ( - "bytes" - "errors" - "fmt" - "os" - "reflect" - - "github.com/cristalhq/aconfig" - "github.com/goccy/go-yaml" -) - -func GenerateYamlTemplate(cfg any, filePath string, opts ...Option) error { - if reflect.ValueOf(cfg).Kind() != reflect.Ptr { - return errors.New("config must be a pointer") - } - - options := newOptions(opts...) - - c := config{ - out: os.Stdout, - exit: os.Exit, - args: os.Args[1:], - options: options, - } - - aconf, err := getAconfig(c) - if err != nil { - return err - } - - loader := aconfig.LoaderFor(cfg, aconf) - - if err := loader.Load(); err != nil { - return err - } - - buf := bytes.NewBuffer(nil) - enc := yaml.NewEncoder(buf, yaml.Indent(2)) - defer enc.Close() - - if err := enc.Encode(cfg); err != nil { - return fmt.Errorf("failed to encode yaml: %w", err) - } - - if err := os.WriteFile(filePath, buf.Bytes(), 0o600); err != nil { - return fmt.Errorf("failed to write file: %w", err) - } - - return nil -} diff --git a/cfg/help.go b/cfg/help.go deleted file mode 100644 index c7ff62a..0000000 --- a/cfg/help.go +++ /dev/null @@ -1,71 +0,0 @@ -package cfg - -import ( - "fmt" - "os" - "strings" - - "github.com/cristalhq/aconfig" -) - -func GenerateDefaultEnvs(cfg any, _ string, opts ...Option) error { - options := newOptions(opts...) - - c := config{ - out: os.Stdout, - exit: os.Exit, - args: os.Args[1:], - options: options, - } - - aconf, err := getAconfig(c) - if err != nil { - return err - } - - loader := aconfig.LoaderFor(cfg, aconf) - - if err := loader.Load(); err != nil { - return err - } - - loader.WalkFields(c.generateDefaultEnvs) - - return nil -} - -func (c *config) generateDefaultEnvs(field aconfig.Field) bool { - value := field.Tag("default") - names := field.Tag("env") - usage := field.Tag("usage") - - current := field - if value == "" { - value = "" - } - - pad := 50 - - var ok bool - for { - if current, ok = current.Parent(); !ok { - break - } - - names = fmt.Sprintf("%s_%s", current.Tag("env"), names) - } - - var line strings.Builder - _, _ = line.WriteString(names) - _, _ = line.WriteString("=") - _, _ = line.WriteString(value) - - if usage != "" { - _, _ = line.WriteString(strings.Repeat(" ", pad-line.Len())) - _, _ = line.WriteString("# " + usage) - } - - c.print(line.String()) - - return true -} diff --git a/cfg/loader.go b/cfg/loader.go deleted file mode 100644 index 09791c4..0000000 --- a/cfg/loader.go +++ /dev/null @@ -1,38 +0,0 @@ -package cfg - -import ( - "errors" - "os" - "reflect" - - "github.com/cristalhq/aconfig" -) - -// GetConfigLoader returns aconfig loader instance. -func GetConfigLoader(cfg any, opts ...Option) (*aconfig.Loader, error) { - if reflect.ValueOf(cfg).Kind() != reflect.Ptr { - return nil, errors.New("config must be a pointer") - } - - options := newOptions(opts...) - - c := config{ - out: os.Stdout, - exit: os.Exit, - args: os.Args[1:], - options: options, - } - - aconf, err := getAconfig(c) - if err != nil { - return nil, err - } - - loader := aconfig.LoaderFor(cfg, aconf) - - if err := loader.Load(); err != nil { - return nil, err - } - - return loader, nil -} diff --git a/cfg/markdown.go b/cfg/markdown.go deleted file mode 100644 index ff5ef7f..0000000 --- a/cfg/markdown.go +++ /dev/null @@ -1,147 +0,0 @@ -package cfg - -import ( - "errors" - "fmt" - "os" - "reflect" - "strings" - "unicode/utf8" - - "github.com/cristalhq/aconfig" -) - -const cellSeparator = "|" - -func GenerateMarkdown(cfg any, filePath string, opts ...Option) error { - if reflect.ValueOf(cfg).Kind() != reflect.Ptr { - return errors.New("config must be a pointer") - } - - options := newOptions(opts...) - - c := config{ - out: os.Stdout, - exit: os.Exit, - args: os.Args[1:], - options: options, - } - - aconf, err := getAconfig(c) - if err != nil { - return err - } - - loader := aconfig.LoaderFor(cfg, aconf) - - if err := loader.Load(); err != nil { - return err - } - - return c.generateMarkdown(loader, filePath) -} - -func (c *config) generateMarkdown(l *aconfig.Loader, filePath string) error { - table := [][]string{ - { - "Name", "Required", "Secret", "Default value", "Usage", "Example", - }, - } - - sizes := make([]int, len(table[0])) - - var lineSize int - for i, cell := range table[0] { - sizes[i] = utf8.RuneCountInString(cell) + 2 - } - - configFields := GetConfigFields(l) - for _, f := range configFields { - envName := f.EnvName - if c.options.loaderConfig.EnvPrefix != "" { - envName = c.options.loaderConfig.EnvPrefix + "_" + envName - } - - cell := []string{ - "`" + envName + "`", - boolIcon(f.IsRequired), - boolIcon(f.IsSecret), - codeBlock(f.DefaultValue), - f.Usage, - codeBlock(f.Example), - } - table = append(table, cell) - - lineSize = 0 - for i, item := range cell { - if size := utf8.RuneCountInString(item); size+2 > sizes[i] { - sizes[i] = size + 2 - } - - lineSize += sizes[i] // recalculate line size - } - } - - var out strings.Builder - _, _ = out.WriteString("# Environments\n\n") - for i, row := range table { - _, _ = out.WriteString(cellSeparator) - - for j, cell := range row { - size := utf8.RuneCountInString(" " + cell + " ") - - data := strings.Repeat(" ", sizes[j]-size) - - _, _ = out.WriteString(" " + cell + " ") - _, _ = out.WriteString(data) - - if len(row)-1 != j { - _, _ = out.WriteString(cellSeparator) - } - } - - if i == 0 { - _, _ = out.WriteString(cellSeparator) - _, _ = out.WriteRune('\n') - - _, _ = out.WriteString(cellSeparator) - for j, item := range sizes { - dashes := strings.Repeat("-", item) - _, _ = out.WriteString(dashes) - - if len(sizes)-1 != j { - _, _ = out.WriteString(cellSeparator) - } - } - } - - _, _ = out.WriteString(cellSeparator) - _, _ = out.WriteRune('\n') - } - - _, _ = fmt.Fprintln(c.out, out.String()) - - if filePath != "" { - if err := os.WriteFile(filePath, []byte(out.String()), 0o600); err != nil { - return err - } - } - - return nil -} - -func boolIcon(value bool) string { - if value { - return "✅" - } - - return " " -} - -func codeBlock(val string) string { - if val == "" { - return val - } - - return "`" + val + "`" -} diff --git a/cfg/options.go b/cfg/options.go deleted file mode 100644 index 2c50ba1..0000000 --- a/cfg/options.go +++ /dev/null @@ -1,78 +0,0 @@ -package cfg - -import ( - "context" - "slices" - - "github.com/cristalhq/aconfig" - "github.com/go-playground/validator/v10" -) - -type Option func(*options) - -type ValidateFn struct { - Tag string - Fn validator.Func - CallValidationEvenIfNull []bool -} - -type Config = aconfig.Config - -type options struct { - loaderConfig aconfig.Config - validate bool - ctx context.Context //nolint:containedctx - validateFuncs []ValidateFn -} - -func newOptions(opts ...Option) *options { - opt := &options{ - validate: true, - ctx: context.Background(), - validateFuncs: make([]ValidateFn, 0), - } - - for _, o := range opts { - o(opt) - } - - return opt -} - -// WithEnvFile - path to dotenv config file. -func WithLoaderConfig(v Config) Option { - return func(o *options) { - o.loaderConfig = v - } -} - -func WithValidate(v bool) Option { - return func(o *options) { - o.validate = v - } -} - -func WithContext(v context.Context) Option { - return func(o *options) { - o.ctx = v - } -} - -func WithValidateFuncs(items ...ValidateFn) Option { - return func(o *options) { - for _, item := range items { - if item.Tag == "" || - item.Fn == nil { - continue - } - - if ok := slices.ContainsFunc(o.validateFuncs, func(el ValidateFn) bool { - return el.Tag == item.Tag - }); ok { - continue - } - - o.validateFuncs = append(o.validateFuncs, item) - } - } -} diff --git a/cfg/tests.go b/cfg/tests.go deleted file mode 100644 index ac4a696..0000000 --- a/cfg/tests.go +++ /dev/null @@ -1,57 +0,0 @@ -package cfg - -import ( - "errors" - "os" - "reflect" - - "github.com/cristalhq/aconfig" -) - -// LoadForTests environment variables from `os env`, flags, `.env`, `.yaml` files and pass it to struct. -// -// Disabled flags detection and any cli features. -// -// For local development use `.env` file from root project. -// -// LoadForTests also call a `Validate` method if it proided. -// -// Example: -// -// var config internalConfig.Config -// if err := cfg.LoadForTests(&config); err != nil { -// logger.Fatalf("could not load configuration: %v", err) -// } -func LoadForTests(cfg any, opts ...Option) error { - if reflect.ValueOf(cfg).Kind() != reflect.Ptr { - return errors.New("config must be a pointer") - } - - options := newOptions(opts...) - - c := config{ - out: os.Stdout, - exit: os.Exit, - args: os.Args[1:], - options: options, - } - - aconf, err := getAconfig(c) - if err != nil { - return err - } - - loader := aconfig.LoaderFor(cfg, aconf) - - if err := loader.Load(); err != nil { - return err - } - - if options.validate { - if err := c.validateEnvs(cfg, loader); err != nil { - return err - } - } - - return nil -} diff --git a/cfg/types.go b/cfg/types.go deleted file mode 100644 index aa413f2..0000000 --- a/cfg/types.go +++ /dev/null @@ -1,13 +0,0 @@ -package cfg - -type ConfigField struct { - Path string - EnvName string - DefaultValue string - Usage string - Example string - ValidateParams string - IsRequired bool - IsSecret bool - DisableValidation bool -} diff --git a/cfg/validate.go b/cfg/validate.go deleted file mode 100644 index 60d51bd..0000000 --- a/cfg/validate.go +++ /dev/null @@ -1,124 +0,0 @@ -package cfg - -import ( - "context" - "errors" - "fmt" - "os" - "reflect" - "strings" - - "github.com/cristalhq/aconfig" - "github.com/go-playground/validator/v10" - "github.com/tkcrm/mx/util/structs" -) - -// ValidateConfig validates config struct with environment variables and custom validation functions. -func ValidateConfig(cfg any, opts ...Option) error { - if reflect.ValueOf(cfg).Kind() != reflect.Ptr { - return errors.New("config must be a pointer") - } - - options := newOptions(opts...) - - c := config{ - out: os.Stdout, - exit: os.Exit, - args: os.Args[1:], - options: options, - } - - aconf, err := getAconfig(c) - if err != nil { - return err - } - - loader := aconfig.LoaderFor(cfg, aconf) - - if err := loader.Load(); err != nil { - return err - } - - if err := c.validateEnvs(cfg, loader); err != nil { - return err - } - - c.print("OK") - - return nil -} - -func (c *config) validateEnvs(cfg any, loader *aconfig.Loader) error { - if err := validateElem(c.options.ctx, cfg); err != nil { - return err - } - - val := reflect.ValueOf(cfg).Elem() - for i := range val.NumField() { - if err := validateElem(c.options.ctx, val.Field(i).Addr().Interface()); err != nil { - return err - } - } - - // init validator - validate := validator.New() - for _, item := range c.options.validateFuncs { - if err := validate.RegisterValidation(item.Tag, item.Fn, item.CallValidationEvenIfNull...); err != nil { - return err - } - } - - // validate struct - errs := []string{} - configFields := GetConfigFields(loader) - for _, f := range configFields { - if f.DisableValidation || f.ValidateParams == "" { - continue - } - - fieldValue, err := structs.LookupString(cfg, f.Path) - if err != nil { - return err - } - - if err := validate.Var(fieldValue.Interface(), f.ValidateParams); err != nil { - errs = append(errs, - strings.ReplaceAll( - err.Error(), - "Key: '' Error:Field validation for ''", - fmt.Sprintf("Validate %s env error:", f.EnvName), - ), - ) - } - } - - if len(errs) > 0 { - return errors.New(strings.Join(errs, "; ")) - } - - return nil -} - -func validateElem(ctx context.Context, elem any) error { - // try to validate with Validate() error - if tmp, ok := elem.(interface { - Validate() error - }); ok { - if err := tmp.Validate(); err != nil { - return err - } - } - - // try to validate with Validate(ctx context.Context) error - if ctx != nil { - if tmp, ok := elem.(interface { - Validate(ctx context.Context) error - }); ok { - if err := tmp.Validate(ctx); err != nil { - return err - } - } - } - - return nil -} diff --git a/cfg/yamlloader/loader.go b/cfg/yamlloader/loader.go deleted file mode 100644 index 60a6533..0000000 --- a/cfg/yamlloader/loader.go +++ /dev/null @@ -1,40 +0,0 @@ -package yamlloader - -import ( - "io/fs" - - "github.com/goccy/go-yaml" -) - -// Decoder of YAML files for aconfig. -type Decoder struct { - fsys fs.FS -} - -// New YAML decoder for aconfig. -func New() *Decoder { return &Decoder{} } - -// Format of the decoder. -func (d *Decoder) Format() string { - return "yaml" -} - -// DecodeFile implements aconfig.FileDecoder. -func (d *Decoder) DecodeFile(filename string) (map[string]any, error) { - f, err := d.fsys.Open(filename) - if err != nil { - return nil, err - } - defer f.Close() - - var raw map[string]any - if err := yaml.NewDecoder(f).Decode(&raw); err != nil { - return nil, err - } - return raw, nil -} - -// DecodeFile implements aconfig.FileDecoder. -func (d *Decoder) Init(fsys fs.FS) { - d.fsys = fsys -} diff --git a/clients/connectrpc_client/go.mod b/clients/connectrpc_client/go.mod index 7f63f19..3725509 100644 --- a/clients/connectrpc_client/go.mod +++ b/clients/connectrpc_client/go.mod @@ -1,11 +1,7 @@ module github.com/tkcrm/mx/clients/connectrpc_client -go 1.23.0 +go 1.26.0 -require github.com/google/go-cmp v0.7.0 // indirect +require connectrpc.com/connect v1.19.1 -require ( - connectrpc.com/connect v1.18.1 - golang.org/x/net v0.38.0 // indirect - google.golang.org/protobuf v1.36.6 // indirect -) +require google.golang.org/protobuf v1.36.11 // indirect diff --git a/clients/connectrpc_client/go.sum b/clients/connectrpc_client/go.sum index 7b0aef5..6dfa443 100644 --- a/clients/connectrpc_client/go.sum +++ b/clients/connectrpc_client/go.sum @@ -1,10 +1,6 @@ -connectrpc.com/connect v1.18.1 h1:PAg7CjSAGvscaf6YZKUefjoih5Z/qYkyaTrBW8xvYPw= -connectrpc.com/connect v1.18.1/go.mod h1:0292hj1rnx8oFrStN7cB4jjVBeqs+Yx5yDIC2prWDO8= +connectrpc.com/connect v1.19.1 h1:R5M57z05+90EfEvCY1b7hBxDVOUl45PrtXtAV2fOC14= +connectrpc.com/connect v1.19.1/go.mod h1:tN20fjdGlewnSFeZxLKb0xwIZ6ozc3OQs2hTXy4du9w= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= -golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= -golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= -golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= -golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= -google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= -google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= diff --git a/clients/grpc_client/go.mod b/clients/grpc_client/go.mod index 5084562..6ae8475 100644 --- a/clients/grpc_client/go.mod +++ b/clients/grpc_client/go.mod @@ -1,13 +1,13 @@ module github.com/tkcrm/mx/clients/grpc_client -go 1.23.0 +go 1.26.0 -require google.golang.org/grpc v1.73.0 +require google.golang.org/grpc v1.79.2 require ( - golang.org/x/net v0.41.0 // indirect - golang.org/x/sys v0.33.0 // indirect - golang.org/x/text v0.26.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect - google.golang.org/protobuf v1.36.6 // indirect + golang.org/x/net v0.52.0 // indirect + golang.org/x/sys v0.42.0 // indirect + golang.org/x/text v0.35.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260316180232-0b37fe3546d5 // indirect + google.golang.org/protobuf v1.36.11 // indirect ) diff --git a/clients/grpc_client/go.sum b/clients/grpc_client/go.sum index e4e04a4..b48ff17 100644 --- a/clients/grpc_client/go.sum +++ b/clients/grpc_client/go.sum @@ -1,5 +1,7 @@ -github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= -github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= @@ -8,27 +10,29 @@ github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= -go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= -go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ= -go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y= -go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M= -go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE= -go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY= -go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg= -go.opentelemetry.io/otel/sdk/metric v1.35.0 h1:1RriWBmCKgkeHEhM7a2uMjMUfP7MsOF5JpUCaEqEI9o= -go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w= -go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs= -go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc= -golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= -golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= -golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= -golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= -golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 h1:fc6jSaCT0vBduLYZHYrBBNY4dsWuvgyff9noRNDdBeE= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= -google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok= -google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc= -google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= -google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= +go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= +go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= +go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48= +go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8= +go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0= +go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs= +go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18= +go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE= +go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8= +go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew= +go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI= +go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA= +golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0= +golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw= +golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= +golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8= +golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA= +gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= +gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260316180232-0b37fe3546d5 h1:aJmi6DVGGIStN9Mobk/tZOOQUBbj0BPjZjjnOdoZKts= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260316180232-0b37fe3546d5/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= +google.golang.org/grpc v1.79.2 h1:fRMD94s2tITpyJGtBBn7MkMseNpOZU8ZxgC3MMBaXRU= +google.golang.org/grpc v1.79.2/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= diff --git a/go.mod b/go.mod index c818094..7d38f86 100644 --- a/go.mod +++ b/go.mod @@ -1,46 +1,34 @@ module github.com/tkcrm/mx -go 1.24.0 +go 1.26.0 require ( - github.com/go-playground/validator/v10 v10.26.0 - github.com/goccy/go-json v0.10.5 - github.com/goccy/go-yaml v1.18.0 - go.uber.org/zap v1.27.0 - golang.org/x/sync v0.18.0 + github.com/goccy/go-json v0.10.6 + go.uber.org/zap v1.27.1 + golang.org/x/sync v0.20.0 ) require ( github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect - github.com/gabriel-vasile/mimetype v1.4.9 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect - github.com/go-playground/locales v0.14.1 // indirect - github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/joho/godotenv v1.5.1 // indirect - github.com/leodido/go-urn v1.4.0 // indirect - github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/prometheus/client_model v0.6.2 // indirect - github.com/prometheus/common v0.64.0 // indirect - github.com/prometheus/procfs v0.16.1 // indirect - go.opentelemetry.io/auto/sdk v1.1.0 // indirect - go.opentelemetry.io/otel v1.36.0 // indirect - go.opentelemetry.io/otel/metric v1.36.0 // indirect - go.opentelemetry.io/otel/trace v1.36.0 // indirect - golang.org/x/crypto v0.45.0 // indirect - golang.org/x/net v0.47.0 // indirect - golang.org/x/sys v0.38.0 // indirect - golang.org/x/text v0.31.0 // indirect - google.golang.org/protobuf v1.36.6 // indirect + github.com/prometheus/common v0.67.5 // indirect + github.com/prometheus/procfs v0.20.1 // indirect + go.opentelemetry.io/auto/sdk v1.2.1 // indirect + go.opentelemetry.io/otel v1.42.0 // indirect + go.opentelemetry.io/otel/metric v1.42.0 // indirect + go.opentelemetry.io/otel/trace v1.42.0 // indirect + go.yaml.in/yaml/v2 v2.4.4 // indirect + golang.org/x/sys v0.42.0 // indirect + google.golang.org/protobuf v1.36.11 // indirect ) require ( - github.com/cristalhq/aconfig v0.18.7 - github.com/cristalhq/aconfig/aconfigdotenv v0.17.1 - github.com/prometheus/client_golang v1.22.0 - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 + github.com/prometheus/client_golang v1.23.2 + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0 go.uber.org/multierr v1.11.0 // indirect ) diff --git a/go.sum b/go.sum index ba968d5..8995d22 100644 --- a/go.sum +++ b/go.sum @@ -2,94 +2,66 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cristalhq/aconfig v0.17.0/go.mod h1:NXaRp+1e6bkO4dJn+wZ71xyaihMDYPtCSvEhMTm/H3E= -github.com/cristalhq/aconfig v0.18.7 h1:ZvgaiSz7D3++TrXN9DrTSWA71eFuig0HhBY32nblLOk= -github.com/cristalhq/aconfig v0.18.7/go.mod h1:9ogrGEt9yU5V4pif/ThkVUfhj8JkdV+iDeahZGgfnDU= -github.com/cristalhq/aconfig/aconfigdotenv v0.17.1 h1:HG2ql5fGe4FLL2fUv6o+o0YRyF1mWEcYkNfWGWD82k4= -github.com/cristalhq/aconfig/aconfigdotenv v0.17.1/go.mod h1:gQIKkh+HkVcODvMNz/cLbH65Pk9b0r4tfolCOsI8G9I= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/gabriel-vasile/mimetype v1.4.9 h1:5k+WDwEsD9eTLL8Tz3L0VnmVh9QxGjRmjBvAG7U/oYY= -github.com/gabriel-vasile/mimetype v1.4.9/go.mod h1:WnSQhFKJuBlRyLiKohA/2DtIlPFAbguNaG7QCHcyGok= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= -github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= -github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= -github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= -github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= -github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.26.0 h1:SP05Nqhjcvz81uJaRfEV0YBSSSGMc/iMaVtFbr3Sw2k= -github.com/go-playground/validator/v10 v10.26.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo= -github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= -github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= -github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw= -github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= +github.com/goccy/go-json v0.10.6 h1:p8HrPJzOakx/mn/bQtjgNjdTcN+/S6FcG2CTtQOrHVU= +github.com/goccy/go-json v0.10.6/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= -github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= -github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= -github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= -github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= -github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q= -github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0= +github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o= +github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg= github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= -github.com/prometheus/common v0.64.0 h1:pdZeA+g617P7oGv1CzdTzyeShxAGrTBsolKNOLQPGO4= -github.com/prometheus/common v0.64.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8= -github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= -github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= -github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= -go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q= -go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg= -go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E= -go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE= -go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs= -go.opentelemetry.io/otel/sdk v1.36.0 h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs= -go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY= -go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis= -go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4= -go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w= -go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA= +github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4= +github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw= +github.com/prometheus/procfs v0.20.1 h1:XwbrGOIplXW/AU3YhIhLODXMJYyC1isLFfYCsTEycfc= +github.com/prometheus/procfs v0.20.1/go.mod h1:o9EMBZGRyvDrSPH1RqdxhojkuXstoe4UlK79eF5TGGo= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= +go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0 h1:OyrsyzuttWTSur2qN/Lm0m2a8yqyIjUVBZcxFPuXq2o= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0/go.mod h1:C2NGBr+kAB4bk3xtMXfZ94gqFDtg/GkI7e9zqGh5Beg= +go.opentelemetry.io/otel v1.42.0 h1:lSQGzTgVR3+sgJDAU/7/ZMjN9Z+vUip7leaqBKy4sho= +go.opentelemetry.io/otel v1.42.0/go.mod h1:lJNsdRMxCUIWuMlVJWzecSMuNjE7dOYyWlqOXWkdqCc= +go.opentelemetry.io/otel/metric v1.42.0 h1:2jXG+3oZLNXEPfNmnpxKDeZsFI5o4J+nz6xUlaFdF/4= +go.opentelemetry.io/otel/metric v1.42.0/go.mod h1:RlUN/7vTU7Ao/diDkEpQpnz3/92J9ko05BIwxYa2SSI= +go.opentelemetry.io/otel/sdk v1.42.0 h1:LyC8+jqk6UJwdrI/8VydAq/hvkFKNHZVIWuslJXYsDo= +go.opentelemetry.io/otel/sdk v1.42.0/go.mod h1:rGHCAxd9DAph0joO4W6OPwxjNTYWghRWmkHuGbayMts= +go.opentelemetry.io/otel/sdk/metric v1.42.0 h1:D/1QR46Clz6ajyZ3G8SgNlTJKBdGp84q9RKCAZ3YGuA= +go.opentelemetry.io/otel/sdk/metric v1.42.0/go.mod h1:Ua6AAlDKdZ7tdvaQKfSmnFTdHx37+J4ba8MwVCYM5hc= +go.opentelemetry.io/otel/trace v1.42.0 h1:OUCgIPt+mzOnaUTpOQcBiM/PLQ/Op7oq6g4LenLmOYY= +go.opentelemetry.io/otel/trace v1.42.0/go.mod h1:f3K9S+IFqnumBkKhRJMeaZeNk9epyhnCmQh/EysQCdc= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= -go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= -golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= -golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= -golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= -golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= -golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= -golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= -golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= -golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= -golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= -google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= -google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= +go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= +go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ= +go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ= +golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= +golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= +golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= +golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/launcher/launcher.go b/launcher/launcher.go index 63307e1..7b17442 100644 --- a/launcher/launcher.go +++ b/launcher/launcher.go @@ -9,8 +9,7 @@ import ( "slices" "sync" - "github.com/tkcrm/mx/ops" - "github.com/tkcrm/mx/service" + "github.com/tkcrm/mx/launcher/ops" signalutil "github.com/tkcrm/mx/util/signal" "golang.org/x/sync/errgroup" ) @@ -66,9 +65,9 @@ func (l *launcher) Run() error { //nolint:cyclop l.opts.OpsConfig.Healthy.AddServicesList(l.servicesRunner.hcServices()) } opsSvcs := ops.New(l.opts.logger, l.opts.OpsConfig) - svcs := make([]*service.Service, len(opsSvcs)) + svcs := make([]*Service, len(opsSvcs)) for i := range opsSvcs { - svcs[i] = service.New(service.WithService(opsSvcs[i])) + svcs[i] = NewService(WithService(opsSvcs[i])) } l.servicesRunner.Register(svcs...) } @@ -85,7 +84,7 @@ func (l *launcher) Run() error { //nolint:cyclop graceWait := new(sync.WaitGroup) graceWait.Add(len(l.servicesRunner.Services())) for i := range l.servicesRunner.Services() { - go func(svc *service.Service) { + go func(svc *Service) { defer graceWait.Done() if err := svc.Start(); err != nil { err := fmt.Errorf("failed to start service [%s]: %w", svc.Name(), err) @@ -108,19 +107,41 @@ func (l *launcher) Run() error { //nolint:cyclop ch := make(chan os.Signal, 1) if l.opts.Signal { signal.Notify(ch, signalutil.Shutdown()...) + defer signal.Stop(ch) } + var forceExitCancel context.CancelFunc + select { // wait on services error case err := <-errChan: + l.cancelFn() + graceWait.Wait() return err // wait on kill signal case <-ch: l.cancelFn() + l.opts.logger.Warnln("graceful shutdown started, send signal again to force exit") + if l.opts.Signal { + var forceCtx context.Context + forceCtx, forceExitCancel = context.WithCancel(context.Background()) + go func() { + select { + case <-ch: + l.opts.logger.Warnln("received second signal, forcing exit") + os.Exit(1) + case <-forceCtx.Done(): + } + }() + } // wait on context cancel case <-l.opts.Context.Done(): } + if forceExitCancel != nil { + defer forceExitCancel() + } + graceWait.Wait() var stopErr error @@ -162,7 +183,7 @@ func (l *launcher) Run() error { //nolint:cyclop } case RunnerServicesSequenceLifo: { - reverted := make([]*service.Service, len(l.servicesRunner.Services())) + reverted := make([]*Service, len(l.servicesRunner.Services())) copy(reverted, l.servicesRunner.Services()) slices.Reverse(reverted) for _, svc := range reverted { diff --git a/ops/config.go b/launcher/ops/config.go similarity index 100% rename from ops/config.go rename to launcher/ops/config.go diff --git a/ops/health.go b/launcher/ops/health.go similarity index 92% rename from ops/health.go rename to launcher/ops/health.go index 4742cba..0795e63 100644 --- a/ops/health.go +++ b/launcher/ops/health.go @@ -8,8 +8,8 @@ import ( "sync" "time" + "github.com/tkcrm/mx/launcher/types" "github.com/tkcrm/mx/logger" - "github.com/tkcrm/mx/service" "github.com/tkcrm/mx/transport/http_transport" ) @@ -26,7 +26,7 @@ var ( ErrHealthCheckServiceStarting = errors.New("service is starting") ) -// health implements service.Service +// health implements service lifecycle // and used as worker pool for HealthChecker. type healthCheckerOpsService struct { log logger.ExtendedLogger @@ -39,10 +39,10 @@ type HealthCheckerConfig struct { Enabled bool `default:"false" usage:"allows to enable health checker" example:"true"` Path string `default:"/healthy" validate:"required" usage:"allows to set custom healthy path" example:"/healthy"` Port string `default:"10000" validate:"required" usage:"allows to set custom healthy port" example:"10000"` - servicesList []service.HealthChecker + servicesList []types.HealthChecker } -func (s *HealthCheckerConfig) AddServicesList(list []service.HealthChecker) { +func (s *HealthCheckerConfig) AddServicesList(list []types.HealthChecker) { s.servicesList = list } @@ -101,7 +101,7 @@ func (s *healthCheckerOpsService) ServeHTTP(w http.ResponseWriter, _ *http.Reque } } -// implementation of service.IService for OPS worker. +// Start implements service lifecycle for OPS health checker worker. func (s *healthCheckerOpsService) Start(ctx context.Context) error { wg := new(sync.WaitGroup) @@ -114,8 +114,7 @@ func (s *healthCheckerOpsService) Start(ctx context.Context) error { s.resp.Store(s.config.servicesList[i].Name(), 0) - // run health checker for each service - go func(checker service.HealthChecker) { + go func(checker types.HealthChecker) { defer wg.Done() name := checker.Name() diff --git a/ops/metrics.go b/launcher/ops/metrics.go similarity index 100% rename from ops/metrics.go rename to launcher/ops/metrics.go diff --git a/ops/ops.go b/launcher/ops/ops.go similarity index 92% rename from ops/ops.go rename to launcher/ops/ops.go index f6f1a28..09bbf05 100644 --- a/ops/ops.go +++ b/launcher/ops/ops.go @@ -9,19 +9,19 @@ import ( "net/http" "strings" + "github.com/tkcrm/mx/launcher/types" "github.com/tkcrm/mx/logger" - "github.com/tkcrm/mx/service" "github.com/tkcrm/mx/transport/http_transport" ) type ops struct { logger logger.ExtendedLogger config Config - services []service.IService + services []types.IService } // New return list with ops services. -func New(log logger.ExtendedLogger, cfg Config) []service.IService { +func New(log logger.ExtendedLogger, cfg Config) []types.IService { s := &ops{ logger: log, config: cfg, @@ -44,7 +44,7 @@ func New(log logger.ExtendedLogger, cfg Config) []service.IService { } if len(services) == 0 { - return []service.IService{} + return []types.IService{} } type muxServer struct { diff --git a/ops/profiler.go b/launcher/ops/profiler.go similarity index 86% rename from ops/profiler.go rename to launcher/ops/profiler.go index 55bcfd4..e202b40 100644 --- a/ops/profiler.go +++ b/launcher/ops/profiler.go @@ -1,3 +1,8 @@ +// It's okay to expose pprof from this binary since the port it is exposed on +// is not accessible from the outside of Kubernetes cluster (only inside of it). +// +// #nosec G108 (CWE-200): Profiling endpoint is automatically exposed on /debug/pprof + package ops import ( diff --git a/ops/sentry/config.go b/launcher/ops/sentry/config.go similarity index 100% rename from ops/sentry/config.go rename to launcher/ops/sentry/config.go diff --git a/ops/sentry/go.mod b/launcher/ops/sentry/go.mod similarity index 50% rename from ops/sentry/go.mod rename to launcher/ops/sentry/go.mod index 4c49b6a..da9d5fe 100644 --- a/ops/sentry/go.mod +++ b/launcher/ops/sentry/go.mod @@ -1,15 +1,15 @@ module github.com/tkcrm/mx/ops/sentry -go 1.23.0 +go 1.25.0 require ( - github.com/getsentry/sentry-go v0.33.0 + github.com/getsentry/sentry-go v0.43.0 github.com/go-ozzo/ozzo-validation/v4 v4.3.0 - go.uber.org/zap v1.27.0 + go.uber.org/zap v1.27.1 ) require ( go.uber.org/multierr v1.11.0 // indirect - golang.org/x/sys v0.33.0 // indirect - golang.org/x/text v0.26.0 // indirect + golang.org/x/sys v0.42.0 // indirect + golang.org/x/text v0.35.0 // indirect ) diff --git a/ops/sentry/go.sum b/launcher/ops/sentry/go.sum similarity index 80% rename from ops/sentry/go.sum rename to launcher/ops/sentry/go.sum index eca48d4..982bcf6 100644 --- a/ops/sentry/go.sum +++ b/launcher/ops/sentry/go.sum @@ -3,8 +3,8 @@ github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496/go.mod h1:o github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/getsentry/sentry-go v0.33.0 h1:YWyDii0KGVov3xOaamOnF0mjOrqSjBqwv48UEzn7QFg= -github.com/getsentry/sentry-go v0.33.0/go.mod h1:C55omcY9ChRQIUcVcGcs+Zdy4ZpQGvNJ7JYHIoSWOtE= +github.com/getsentry/sentry-go v0.43.0 h1:XbXLpFicpo8HmBDaInk7dum18G9KSLcjZiyUKS+hLW4= +github.com/getsentry/sentry-go v0.43.0/go.mod h1:XDotiNZbgf5U8bPDUAfvcFmOnMQQceESxyKaObSssW0= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-ozzo/ozzo-validation/v4 v4.3.0 h1:byhDUpfEwjsVQb1vBunvIjh2BHQ9ead57VkAEY4V+Es= @@ -25,12 +25,12 @@ go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= -go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= -golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= -golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= -golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= +go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= +go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= +golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8= +golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/ops/sentry/sentry.go b/launcher/ops/sentry/sentry.go similarity index 100% rename from ops/sentry/sentry.go rename to launcher/ops/sentry/sentry.go diff --git a/ops/types.go b/launcher/ops/types.go similarity index 100% rename from ops/types.go rename to launcher/ops/types.go diff --git a/launcher/options.go b/launcher/options.go index 73b6da4..2c2801f 100644 --- a/launcher/options.go +++ b/launcher/options.go @@ -3,8 +3,8 @@ package launcher import ( "context" + "github.com/tkcrm/mx/launcher/ops" "github.com/tkcrm/mx/logger" - "github.com/tkcrm/mx/ops" ) type Option func(*Options) diff --git a/service/service.go b/launcher/service.go similarity index 77% rename from service/service.go rename to launcher/service.go index ec2ae73..4407916 100644 --- a/service/service.go +++ b/launcher/service.go @@ -1,36 +1,28 @@ -package service +package launcher import ( "context" - "os" - "os/signal" "time" - - signalutil "github.com/tkcrm/mx/util/signal" ) -type IService interface { - Name() string - Start(ctx context.Context) error - Stop(ctx context.Context) error -} - +// Service wraps a lifecycle-managed unit with Start/Stop functions and hooks. type Service struct { - opts Options + opts ServiceOptions isStarted bool isStopped bool } -func New(opts ...Option) *Service { +// NewService creates a new Service. +func NewService(opts ...ServiceOption) *Service { return &Service{ - opts: newOptions(opts...), + opts: newServiceOptions(opts...), } } func (s Service) Name() string { return s.opts.Name } -func (s *Service) Options() *Options { return &s.opts } +func (s *Service) Options() *ServiceOptions { return &s.opts } func (s Service) String() string { return "mx" } @@ -44,7 +36,6 @@ func (s *Service) Start() error { return nil } - // skip if service already started if s.isStarted { return nil } @@ -75,18 +66,9 @@ func (s *Service) Start() error { } } - ch := make(chan os.Signal, 1) - if s.opts.Signal { - signal.Notify(ch, signalutil.Shutdown()...) - } - select { - // wait on service error case err := <-errChan: return err - // wait on kill signal - case <-ch: - // wait on context cancel case <-s.opts.Context.Done(): } @@ -111,7 +93,6 @@ func (s *Service) Stop() error { return nil } - // skip if service already stopped or not started if s.isStopped || !s.isStarted { return nil } @@ -142,13 +123,10 @@ func (s *Service) Stop() error { }() select { - // success stop case <-doneChan: s.opts.Logger.Infof("service [%s] was stopped", s.Name()) - // stop with error case err := <-errChan: return err - // stop by context case <-ctx.Done(): s.opts.Logger.Infof("failed to stop service [%s]. stop by timeout", s.Name()) } diff --git a/launcher/service_options.go b/launcher/service_options.go new file mode 100644 index 0000000..e753981 --- /dev/null +++ b/launcher/service_options.go @@ -0,0 +1,179 @@ +package launcher + +import ( + "context" + "errors" + "time" + + "github.com/tkcrm/mx/launcher/types" + "github.com/tkcrm/mx/logger" +) + +const defaultServiceName = "unknown" + +// ServiceOptions holds configuration for a Service. +type ServiceOptions struct { + Logger logger.Logger + + Name string + Enabled bool + HealthChecker types.HealthChecker + + StartFn func(ctx context.Context) error + StopFn func(ctx context.Context) error + + // Before and After funcs + BeforeStart []func() error + BeforeStop []func() error + AfterStart []func() error + AfterStartFinished []func() error + AfterStop []func() error + + Context context.Context //nolint:containedctx + + // Default 10 seconds + ShutdownTimeout time.Duration +} + +func (s *ServiceOptions) Validate() error { + if s.Logger == nil { + return errors.New("undefined logger") + } + + if s.Name == "" { + return errors.New("empty name") + } + + if s.StartFn == nil { + return errors.New("undefined Start func") + } + + if s.StopFn == nil { + return errors.New("undefined Stop func") + } + + if s.Context == nil { + return errors.New("undefined context") + } + + return nil +} + +func newServiceOptions(opts ...ServiceOption) ServiceOptions { + opt := ServiceOptions{ + Logger: logger.New(), + + Name: defaultServiceName, + Enabled: true, + + BeforeStart: make([]func() error, 0), + BeforeStop: make([]func() error, 0), + AfterStart: make([]func() error, 0), + AfterStartFinished: make([]func() error, 0), + AfterStop: make([]func() error, 0), + + ShutdownTimeout: time.Second * 10, + } + + for _, o := range opts { + o(&opt) + } + + return opt +} + +// ServiceOption is a function that configures a ServiceOptions. +type ServiceOption func(o *ServiceOptions) + +// WithServiceName sets the name of the service. +func WithServiceName(n string) ServiceOption { + return func(o *ServiceOptions) { o.Name = n } +} + +func WithServiceContext(ctx context.Context) ServiceOption { + return func(o *ServiceOptions) { o.Context = ctx } +} + +func WithServiceLogger(l logger.Logger) ServiceOption { + return func(o *ServiceOptions) { o.Logger = l } +} + +// WithStart sets the start function of the service. +func WithStart(fn func(context.Context) error) ServiceOption { + return func(o *ServiceOptions) { o.StartFn = fn } +} + +// WithStop sets the stop function of the service. +func WithStop(fn func(context.Context) error) ServiceOption { + return func(o *ServiceOptions) { o.StopFn = fn } +} + +// WithEnabled sets the enabled state of the service. +func WithEnabled(v bool) ServiceOption { + return func(o *ServiceOptions) { o.Enabled = v } +} + +// WithShutdownTimeout sets the shutdown timeout of the service. +func WithShutdownTimeout(v time.Duration) ServiceOption { + return func(o *ServiceOptions) { o.ShutdownTimeout = v } +} + +// WithService wraps any value that implements Name/Start/Stop/Enabled/HealthChecker. +func WithService(svc any) ServiceOption { + return func(o *ServiceOptions) { + if impl, ok := svc.(interface{ Name() string }); ok { + o.Name = impl.Name() + } + + if impl, ok := svc.(interface{ Start(_ context.Context) error }); ok { + o.StartFn = impl.Start + } + + if impl, ok := svc.(interface{ Stop(_ context.Context) error }); ok { + o.StopFn = impl.Stop + } + + if impl, ok := svc.(types.Enabler); ok { + o.Enabled = impl.Enabled() + } + + if impl, ok := svc.(types.HealthChecker); ok { + o.HealthChecker = impl + } + } +} + +// WithServiceBeforeStart runs fn before service starts. +func WithServiceBeforeStart(fn func() error) ServiceOption { + return func(o *ServiceOptions) { + o.BeforeStart = append(o.BeforeStart, fn) + } +} + +// WithServiceBeforeStop runs fn before service stops. +func WithServiceBeforeStop(fn func() error) ServiceOption { + return func(o *ServiceOptions) { + o.BeforeStop = append(o.BeforeStop, fn) + } +} + +// WithServiceAfterStart runs fn after service starts. +func WithServiceAfterStart(fn func() error) ServiceOption { + return func(o *ServiceOptions) { + o.AfterStart = append(o.AfterStart, fn) + } +} + +// WithServiceAfterStartFinished runs fn after the service Start func finishes. +func WithServiceAfterStartFinished(fn func() error) ServiceOption { + return func(o *ServiceOptions) { + o.AfterStartFinished = append(o.AfterStartFinished, fn) + } +} + +// WithServiceAfterStop runs fn after service stops. +func WithServiceAfterStop(fn func() error) ServiceOption { + return func(o *ServiceOptions) { + o.AfterStop = append(o.AfterStop, fn) + } +} diff --git a/service/pingpong/logger.go b/launcher/services/pingpong/logger.go similarity index 100% rename from service/pingpong/logger.go rename to launcher/services/pingpong/logger.go diff --git a/service/pingpong/options.go b/launcher/services/pingpong/options.go similarity index 100% rename from service/pingpong/options.go rename to launcher/services/pingpong/options.go diff --git a/service/pingpong/ping_pong.go b/launcher/services/pingpong/ping_pong.go similarity index 93% rename from service/pingpong/ping_pong.go rename to launcher/services/pingpong/ping_pong.go index 7a28a5d..c7dfd90 100644 --- a/service/pingpong/ping_pong.go +++ b/launcher/services/pingpong/ping_pong.go @@ -5,7 +5,7 @@ import ( "sync" "time" - "github.com/tkcrm/mx/service" + "github.com/tkcrm/mx/launcher/types" ) var ( @@ -72,4 +72,4 @@ func (p *PingPong) Stop(_ context.Context) error { return nil } -var _ service.IService = (*PingPong)(nil) +var _ types.IService = (*PingPong)(nil) diff --git a/launcher/services_runner.go b/launcher/services_runner.go index 7e778e3..85283b7 100644 --- a/launcher/services_runner.go +++ b/launcher/services_runner.go @@ -3,8 +3,8 @@ package launcher import ( "context" + "github.com/tkcrm/mx/launcher/types" "github.com/tkcrm/mx/logger" - "github.com/tkcrm/mx/service" ) type RunnerServicesSequence int @@ -16,33 +16,33 @@ const ( ) type IServicesRunner interface { - // Register servicse - Register(services ...*service.Service) + // Register services + Register(services ...*Service) // Services return all registered services - Services() []*service.Service + Services() []*Service } type servicesRunner struct { logger logger.Logger - services []*service.Service + services []*Service ctx context.Context //nolint:containedctx } func newServicesRunner(ctx context.Context, logger logger.Logger) *servicesRunner { return &servicesRunner{ logger: logger, - services: make([]*service.Service, 0), + services: make([]*Service, 0), ctx: ctx, } } -func (s *servicesRunner) Register(services ...*service.Service) { +func (s *servicesRunner) Register(services ...*Service) { for _, svc := range services { s.registerService(svc) } } -func (s *servicesRunner) registerService(svc *service.Service) { +func (s *servicesRunner) registerService(svc *Service) { if svc == nil { s.logger.Error("trying to register nil service") return @@ -73,13 +73,13 @@ func (s *servicesRunner) registerService(svc *service.Service) { s.services = append(s.services, svc) } -func (s *servicesRunner) Services() []*service.Service { +func (s *servicesRunner) Services() []*Service { return s.services } -// hcServices return services that implements HealthChecker interface. -func (s *servicesRunner) hcServices() []service.HealthChecker { - services := []service.HealthChecker{} +// hcServices return services that implement the HealthChecker interface. +func (s *servicesRunner) hcServices() []types.HealthChecker { + services := []types.HealthChecker{} for _, svc := range s.services { if svc.Options().HealthChecker != nil { services = append(services, svc.Options().HealthChecker) diff --git a/launcher/types/types.go b/launcher/types/types.go new file mode 100644 index 0000000..4a7e37b --- /dev/null +++ b/launcher/types/types.go @@ -0,0 +1,26 @@ +package types + +import ( + "context" + "time" +) + +// IService is the interface that wraps the basic service lifecycle methods. +type IService interface { + Name() string + Start(ctx context.Context) error + Stop(ctx context.Context) error +} + +// HealthChecker provides functionality to check health of any entity +// that implements this interface. +type HealthChecker interface { + Name() string + Interval() time.Duration + Healthy(ctx context.Context) error +} + +// Enabler is the interface that provides enabled state of a service. +type Enabler interface { + Enabled() bool +} diff --git a/logger/logger.go b/logger/logger.go index 48dec92..f79e72b 100644 --- a/logger/logger.go +++ b/logger/logger.go @@ -84,7 +84,7 @@ func With(l Logger, args ...any) Logger { lg.appVersion, lg.zapConfig, lg.options, - lg.sugaredLogger.With(args...), + lg.With(args...), } } @@ -103,7 +103,7 @@ func WithExtended(l ExtendedLogger, args ...any) ExtendedLogger { lg.appVersion, lg.zapConfig, lg.options, - lg.sugaredLogger.With(args...), + lg.With(args...), } } diff --git a/service/enabler.go b/service/enabler.go deleted file mode 100644 index 3044fec..0000000 --- a/service/enabler.go +++ /dev/null @@ -1,5 +0,0 @@ -package service - -type Enabler interface { - Enabled() bool -} diff --git a/service/health.go b/service/health.go deleted file mode 100644 index b649bc2..0000000 --- a/service/health.go +++ /dev/null @@ -1,14 +0,0 @@ -package service - -import ( - "context" - "time" -) - -// HealthChecker provides functionality to check health of any entity -// that implement this interface. -type HealthChecker interface { - Name() string - Interval() time.Duration - Healthy(ctx context.Context) error -} diff --git a/service/options.go b/service/options.go deleted file mode 100644 index 8a6781b..0000000 --- a/service/options.go +++ /dev/null @@ -1,187 +0,0 @@ -package service - -import ( - "context" - "errors" - "time" - - "github.com/tkcrm/mx/logger" -) - -const ( - defaultServiceName = "unknown" -) - -// Options for service. -type Options struct { - Logger logger.Logger - - Name string - Enabled bool - HealthChecker HealthChecker - - StartFn func(ctx context.Context) error - StopFn func(ctx context.Context) error - - // Before and After funcs - BeforeStart []func() error - BeforeStop []func() error - AfterStart []func() error - AfterStartFinished []func() error - AfterStop []func() error - - Signal bool - - Context context.Context //nolint:containedctx - - // Default 10 seconds - ShutdownTimeout time.Duration -} - -func (s *Options) Validate() error { - if s.Logger == nil { - return errors.New("undefined logger") - } - - if s.Name == "" { - return errors.New("empty name") - } - - if s.StartFn == nil { - return errors.New("undefined Start func") - } - - if s.StopFn == nil { - return errors.New("undefined Stop func") - } - - if s.Context == nil { - return errors.New("undefined context") - } - - return nil -} - -func newOptions(opts ...Option) Options { - opt := Options{ - Logger: logger.New(), - - Name: defaultServiceName, - Enabled: true, - - BeforeStart: make([]func() error, 0), - BeforeStop: make([]func() error, 0), - AfterStart: make([]func() error, 0), - AfterStartFinished: make([]func() error, 0), - AfterStop: make([]func() error, 0), - - Signal: true, - - ShutdownTimeout: time.Second * 10, - } - - for _, o := range opts { - o(&opt) - } - - return opt -} - -type Option func(o *Options) - -// HandleSignal toggles automatic installation of the signal handler that -// traps TERM, INT, and QUIT. Users of this feature to disable the signal -// handler, should control liveness of the service through the context. -func WithSignal(b bool) Option { - return func(o *Options) { o.Signal = b } -} - -// Name of the service. -func WithName(n string) Option { - return func(o *Options) { o.Name = n } -} - -func WithContext(ctx context.Context) Option { - return func(o *Options) { o.Context = ctx } -} - -func WithLogger(l logger.Logger) Option { - return func(o *Options) { o.Logger = l } -} - -func WithStart(fn func(context.Context) error) Option { - return func(o *Options) { o.StartFn = fn } -} - -func WithStop(fn func(context.Context) error) Option { - return func(o *Options) { o.StopFn = fn } -} - -func WithEnabled(v bool) Option { - return func(o *Options) { o.Enabled = v } -} - -func WithShutdownTimeout(v time.Duration) Option { - return func(o *Options) { o.ShutdownTimeout = v } -} - -func WithService(svc any) Option { - return func(o *Options) { - if impl, ok := svc.(interface{ Name() string }); ok { - o.Name = impl.Name() - } - - if impl, ok := svc.(interface{ Start(_ context.Context) error }); ok { - o.StartFn = impl.Start - } - - if impl, ok := svc.(interface{ Stop(_ context.Context) error }); ok { - o.StopFn = impl.Stop - } - - if impl, ok := svc.(Enabler); ok { - o.Enabled = impl.Enabled() - } - - if impl, ok := svc.(HealthChecker); ok { - o.HealthChecker = impl - } - } -} - -// Before and Afters - -// WithBeforeStart run funcs before service starts. -func WithBeforeStart(fn func() error) Option { - return func(o *Options) { - o.BeforeStart = append(o.BeforeStart, fn) - } -} - -// WithBeforeStop run funcs before service stops. -func WithBeforeStop(fn func() error) Option { - return func(o *Options) { - o.BeforeStop = append(o.BeforeStop, fn) - } -} - -// WithAfterStart run funcs after service starts. -func WithAfterStart(fn func() error) Option { - return func(o *Options) { - o.AfterStart = append(o.AfterStart, fn) - } -} - -// WithAfterStartFinished run funcs after was finished service start func. -func WithAfterStartFinished(fn func() error) Option { - return func(o *Options) { - o.AfterStartFinished = append(o.AfterStartFinished, fn) - } -} - -// WithAfterStop run funcs after service stops. -func WithAfterStop(fn func() error) Option { - return func(o *Options) { - o.AfterStop = append(o.AfterStop, fn) - } -} diff --git a/testutils/print.go b/testutils/print.go deleted file mode 100644 index 30a81ce..0000000 --- a/testutils/print.go +++ /dev/null @@ -1,14 +0,0 @@ -package testutils - -import ( - "fmt" - - "github.com/goccy/go-json" -) - -func PrintJSON(v any) { - b, _ := json.MarshalIndent(v, "", " ") - if len(b) != 0 { - fmt.Println(string(b)) - } -} diff --git a/transport/connectrpc_transport/go.mod b/transport/connectrpc_transport/go.mod index 4392168..ea55672 100644 --- a/transport/connectrpc_transport/go.mod +++ b/transport/connectrpc_transport/go.mod @@ -1,15 +1,15 @@ module github.com/tkcrm/mx/transport/connectrpc_transport -go 1.23.0 +go 1.26.0 require ( - connectrpc.com/connect v1.18.1 + connectrpc.com/connect v1.19.1 connectrpc.com/grpcreflect v1.3.0 - github.com/tkcrm/mx v0.2.33 + github.com/tkcrm/mx v0.2.34 ) require ( go.uber.org/multierr v1.11.0 // indirect - go.uber.org/zap v1.27.0 // indirect - google.golang.org/protobuf v1.36.6 // indirect + go.uber.org/zap v1.27.1 // indirect + google.golang.org/protobuf v1.36.11 // indirect ) diff --git a/transport/connectrpc_transport/go.sum b/transport/connectrpc_transport/go.sum index dc9aa49..1f68eaf 100644 --- a/transport/connectrpc_transport/go.sum +++ b/transport/connectrpc_transport/go.sum @@ -1,28 +1,24 @@ -connectrpc.com/connect v1.18.1 h1:PAg7CjSAGvscaf6YZKUefjoih5Z/qYkyaTrBW8xvYPw= -connectrpc.com/connect v1.18.1/go.mod h1:0292hj1rnx8oFrStN7cB4jjVBeqs+Yx5yDIC2prWDO8= +connectrpc.com/connect v1.19.1 h1:R5M57z05+90EfEvCY1b7hBxDVOUl45PrtXtAV2fOC14= +connectrpc.com/connect v1.19.1/go.mod h1:tN20fjdGlewnSFeZxLKb0xwIZ6ozc3OQs2hTXy4du9w= connectrpc.com/grpcreflect v1.3.0 h1:Y4V+ACf8/vOb1XOc251Qun7jMB75gCUNw6llvB9csXc= connectrpc.com/grpcreflect v1.3.0/go.mod h1:nfloOtCS8VUQOQ1+GTdFzVg2CJo4ZGaat8JIovCtDYs= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/tkcrm/mx v0.2.33 h1:3Ht1Pe40iBQ1vmteQIeqhoUqMnSHimQa2FOTNkC4Buc= -github.com/tkcrm/mx v0.2.33/go.mod h1:pT9UrKcRSnxZYEUN8+7GzuSot5osnsDuzCA9YUeTOUQ= +github.com/tkcrm/mx v0.2.34 h1:reTg836KS00FI+QMBTQIa2wh6/Z28PE7cHBtTw7Y5nQ= +github.com/tkcrm/mx v0.2.34/go.mod h1:9N8UrILT8mg0IWb2MMtq2MqOMW1CQVIMmEh9ML37N+0= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= -go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= -golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= -golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= -golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= -golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= -google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= -google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= +go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= +go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/transport/grpc_transport/go.mod b/transport/grpc_transport/go.mod index 4d7c389..b4d8eda 100644 --- a/transport/grpc_transport/go.mod +++ b/transport/grpc_transport/go.mod @@ -1,26 +1,27 @@ module github.com/tkcrm/mx/transport/grpc_transport -go 1.23.0 +go 1.26.0 require ( - github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.2 - github.com/tkcrm/mx v0.2.33 - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 - google.golang.org/grpc v1.73.0 + github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.3 + github.com/tkcrm/mx v0.2.34 + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.67.0 + google.golang.org/grpc v1.79.2 ) require ( + github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect - go.opentelemetry.io/auto/sdk v1.1.0 // indirect - go.opentelemetry.io/otel v1.36.0 // indirect - go.opentelemetry.io/otel/metric v1.36.0 // indirect - go.opentelemetry.io/otel/trace v1.36.0 // indirect + go.opentelemetry.io/auto/sdk v1.2.1 // indirect + go.opentelemetry.io/otel v1.42.0 // indirect + go.opentelemetry.io/otel/metric v1.42.0 // indirect + go.opentelemetry.io/otel/trace v1.42.0 // indirect go.uber.org/multierr v1.11.0 // indirect - go.uber.org/zap v1.27.0 // indirect - golang.org/x/net v0.41.0 // indirect - golang.org/x/sys v0.33.0 // indirect - golang.org/x/text v0.26.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect - google.golang.org/protobuf v1.36.6 // indirect + go.uber.org/zap v1.27.1 // indirect + golang.org/x/net v0.52.0 // indirect + golang.org/x/sys v0.42.0 // indirect + golang.org/x/text v0.35.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260316180232-0b37fe3546d5 // indirect + google.golang.org/protobuf v1.36.11 // indirect ) diff --git a/transport/grpc_transport/go.sum b/transport/grpc_transport/go.sum index 3828d62..c0d6774 100644 --- a/transport/grpc_transport/go.sum +++ b/transport/grpc_transport/go.sum @@ -1,3 +1,5 @@ +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= @@ -11,45 +13,47 @@ github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.2 h1:sGm2vDRFUrQJO/Veii4h4zG2vvqG6uWNkBHSTqXOZk0= -github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.2/go.mod h1:wd1YpapPLivG6nQgbf7ZkG1hhSOXDhhn4MLTknx2aAc= +github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.3 h1:B+8ClL/kCQkRiU82d9xajRPKYMrB7E0MbtzWVi1K4ns= +github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.3/go.mod h1:NbCUVmiS4foBGBHOYlCT25+YmGpJ32dZPi75pGEUpj4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/tkcrm/mx v0.2.33 h1:3Ht1Pe40iBQ1vmteQIeqhoUqMnSHimQa2FOTNkC4Buc= -github.com/tkcrm/mx v0.2.33/go.mod h1:pT9UrKcRSnxZYEUN8+7GzuSot5osnsDuzCA9YUeTOUQ= -go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= -go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 h1:q4XOmH/0opmeuJtPsbFNivyl7bCt7yRBbeEm2sC/XtQ= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0/go.mod h1:snMWehoOh2wsEwnvvwtDyFCxVeDAODenXHtn5vzrKjo= -go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg= -go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E= -go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE= -go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs= -go.opentelemetry.io/otel/sdk v1.36.0 h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs= -go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY= -go.opentelemetry.io/otel/sdk/metric v1.35.0 h1:1RriWBmCKgkeHEhM7a2uMjMUfP7MsOF5JpUCaEqEI9o= -go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w= -go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w= -go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/tkcrm/mx v0.2.34 h1:reTg836KS00FI+QMBTQIa2wh6/Z28PE7cHBtTw7Y5nQ= +github.com/tkcrm/mx v0.2.34/go.mod h1:9N8UrILT8mg0IWb2MMtq2MqOMW1CQVIMmEh9ML37N+0= +go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= +go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.67.0 h1:yI1/OhfEPy7J9eoa6Sj051C7n5dvpj0QX8g4sRchg04= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.67.0/go.mod h1:NoUCKYWK+3ecatC4HjkRktREheMeEtrXoQxrqYFeHSc= +go.opentelemetry.io/otel v1.42.0 h1:lSQGzTgVR3+sgJDAU/7/ZMjN9Z+vUip7leaqBKy4sho= +go.opentelemetry.io/otel v1.42.0/go.mod h1:lJNsdRMxCUIWuMlVJWzecSMuNjE7dOYyWlqOXWkdqCc= +go.opentelemetry.io/otel/metric v1.42.0 h1:2jXG+3oZLNXEPfNmnpxKDeZsFI5o4J+nz6xUlaFdF/4= +go.opentelemetry.io/otel/metric v1.42.0/go.mod h1:RlUN/7vTU7Ao/diDkEpQpnz3/92J9ko05BIwxYa2SSI= +go.opentelemetry.io/otel/sdk v1.42.0 h1:LyC8+jqk6UJwdrI/8VydAq/hvkFKNHZVIWuslJXYsDo= +go.opentelemetry.io/otel/sdk v1.42.0/go.mod h1:rGHCAxd9DAph0joO4W6OPwxjNTYWghRWmkHuGbayMts= +go.opentelemetry.io/otel/sdk/metric v1.42.0 h1:D/1QR46Clz6ajyZ3G8SgNlTJKBdGp84q9RKCAZ3YGuA= +go.opentelemetry.io/otel/sdk/metric v1.42.0/go.mod h1:Ua6AAlDKdZ7tdvaQKfSmnFTdHx37+J4ba8MwVCYM5hc= +go.opentelemetry.io/otel/trace v1.42.0 h1:OUCgIPt+mzOnaUTpOQcBiM/PLQ/Op7oq6g4LenLmOYY= +go.opentelemetry.io/otel/trace v1.42.0/go.mod h1:f3K9S+IFqnumBkKhRJMeaZeNk9epyhnCmQh/EysQCdc= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= -go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= -golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= -golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= -golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= -golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= -golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 h1:fc6jSaCT0vBduLYZHYrBBNY4dsWuvgyff9noRNDdBeE= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= -google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok= -google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc= -google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= -google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= +go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= +go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0= +golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw= +golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= +golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8= +golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA= +gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= +gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260316180232-0b37fe3546d5 h1:aJmi6DVGGIStN9Mobk/tZOOQUBbj0BPjZjjnOdoZKts= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260316180232-0b37fe3546d5/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= +google.golang.org/grpc v1.79.2 h1:fRMD94s2tITpyJGtBBn7MkMseNpOZU8ZxgC3MMBaXRU= +google.golang.org/grpc v1.79.2/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/util/signal/signal.go b/util/signal/signal.go index 3fc28e0..3032613 100644 --- a/util/signal/signal.go +++ b/util/signal/signal.go @@ -8,6 +8,6 @@ import ( // Shutdown signals returns all the signals that are being watched for to shut down services. func Shutdown() []os.Signal { return []os.Signal{ - syscall.SIGTERM, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGKILL, + syscall.SIGTERM, syscall.SIGINT, syscall.SIGQUIT, } }