【问题标题】:Using uber fx to provide an interface使用uber fx提供接口
【发布时间】:2022-11-04 12:22:05
【问题描述】:

我正在尝试使用 uber fx 为 go 微服务项目进行依赖注入。

因为所有的微服务都需要构建一个基础服务器,并设置各种配置选项(常用中间件、缓冲区大小等)(我使用的是fiber)。但是这些不同的微服务也有微服务独有的配置选项。也许是数据库连接字符串、jwt 键等。

我创建了一个接口以在创建通用基础应用程序的共享函数中使用,具有通用选项,但是任何需要配置结构依赖项的函数都会失败,因为需要该微服务的特定配置版本。

无法构建 *fiber.App:缺少函数“some-path/http”的依赖项。CreateServer(some-path/http/http.go:65):缺少类型:*http.Config 退出状态 1

最小的例子:

http/http.go

package http

import (
    "time"

    "github.com/gofiber/fiber/v2"
)


type BaseConfig interface {
    GetPort() string
    GetTimeout() int
}

type Config struct {
    Port           string `env:"LISTEN_ADDR" envDefault:":3000"`
    Timeout        uint64 `env:"TIMEOUT" envDefault:"10"`
}

func (c *Config) GetPort() string {
    return c.Port
}

func (c *Config) GetTimeout() int {
    return int(c.Timeout)
}

func CreateServer(config *Config) *fiber.App {
    fiberConfig := fiber.Config{
        ReadTimeout:    time.Second * time.Duration(config.GetTimeout()),
        WriteTimeout:   time.Second * time.Duration(config.GetTimeout()),
    }

    app := fiber.New(fiberConfig)

    // do setup and other stuff

    return app
}

一些服务/配置/config.go

package config

import (
    "github.com/caarlos0/env/v6"
    "github.com/rs/zerolog/log"
)

type Config struct {
    Port                string        `env:"LISTEN_ADDR" envDefault:":3000"`
    Timeout             uint64        `env:"TIMEOUT" envDefault:"10"`
    // some service specific stuff as well
}

func Parse() (*Config, error) {
    cfg := Config{}

    if err := env.Parse(&cfg); err != nil {
        return nil, err
    }

    return &cfg, nil
}

func (c *Config) GetPort() string {
    return c.Port
}

func (c *Config) GetTimeout() int {
    return int(c.Timeout)
}

一些服务/main.go

package main

import (
    "context"
    "time"

    "some-path/http"
    "some-path/config"
    "some-path/controllers"
    "github.com/gofiber/fiber/v2"
    "go.uber.org/fx"
)

func main() {

    opts := []fx.Option{}
    opts = append(opts, provideOptions()...)
    opts = append(opts, fx.Invoke(run))

    app := fx.New(opts...)

    app.Run()
}

func provideOptions() []fx.Option {
    return []fx.Option{
        fx.Invoke(utils.ConfigureLogger),
        fx.Provide(config.Parse),
        fx.Invoke(controllers.SomeController),
    }
}

func run(app *fiber.App, config *config.Config, lc fx.Lifecycle) {
    lc.Append(fx.Hook{
        OnStart: func(ctx context.Context) error {
            errChan := make(chan error)

            go func() {
                errChan <- app.Listen(config.Port)
            }()

            select {
            case err := <-errChan:
                return err
            case <-time.After(100 * time.Millisecond):
                return nil
            }
        },
        OnStop: func(ctx context.Context) error {
            return app.Shutdown()
        },
    })
}

一些路径/控制器/一些控制器.go

package controllers

import "some-path/config"

func SomeController (config *config.Config) {
    // do stuff
}

【问题讨论】:

  • 尝试将func provideOptions() 中的fx.Provide(config.Parse) 更改为fx. Invoke(config.Parse)
  • @RahmatFathoni 不行。

标签: go dependency-injection go-uber-fx


【解决方案1】:

您缺少 *http.Config 对象,创建一个返回该对象的函数,例如NewConfig()

package http

import (
    "time"

    "github.com/caarlos0/env/v6"
    "github.com/gofiber/fiber/v2"
)

type BaseConfig interface {
    GetPort() string
    GetTimeout() int
}

type Config struct {
    Port    string `env:"LISTEN_ADDR" envDefault:":3000"`
    Timeout uint64 `env:"TIMEOUT" envDefault:"10"`
}

func NewConfig() (*Config, error) {
    cfg := Config{}

    if err := env.Parse(&cfg); err != nil {
        return nil, err
    }

    return &cfg, nil
}

func (c *Config) GetPort() string {
    return c.Port
}

func (c *Config) GetTimeout() int {
    return int(c.Timeout)
}

func CreateServer(config *Config) *fiber.App {
    fiberConfig := fiber.Config{
        ReadTimeout:  time.Second * time.Duration(config.GetTimeout()),
        WriteTimeout: time.Second * time.Duration(config.GetTimeout()),
    }

    app := fiber.New(fiberConfig)

    // do setup and other stuff

    return app
}

然后更改您的provideOptions(),可能是这样的:

func provideOptions() []fx.Option {
    return []fx.Option{
        fx.Invoke(utils.ConfigureLogger),
        fx.Provide(config.Parse, http.NewConfig),
        fx.Invoke(controllers.SomeController),
        fx.Provide(http.CreateServer),
    }
}

【讨论】:

  • 我无法从另一个微服务导入配置,创建多个配置和使用接口的全部目的是消除微服务之间的依赖关系。
  • 因此,您必须创建一个返回 http.Config 指针的方法,然后将其添加到 provideOptions
猜你喜欢
  • 2022-09-24
  • 2018-09-15
  • 2011-05-11
  • 2015-02-05
  • 1970-01-01
  • 2012-07-07
  • 1970-01-01
  • 1970-01-01
  • 2012-02-18
相关资源
最近更新 更多