使用uber fx提供接口
我正在尝试使用 uber fx 为 go 微服务项目进行依赖注入。
由于所有微服务都需要构建一个基础服务器,并设置各种配置选项(通用中间件、缓冲区大小等)(我使用 纤维)。但这些不同的微服务也有微服务特有的配置选项。也许是数据库连接字符串、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
}
some-service/config/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)
}
some-service/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()
},
})
}
some-path/controllers/some-controller.go
package controllers
import "some-path/config"
func SomeController (config *config.Config) {
// do stuff
}
I am attempting to use uber fx to do dependency injection for a go microservice project.
Since all the microservices will need to construct a base server, and set up a variety of config options (common middleware, buffer sizes etc) (I am using fiber). But these different microservices also have config options unique to the microservice. Maybe a database connection string, jwt keys etc.
I created an interface to use in the shared function that creates the common base app, with the common options, but any function needing a dependency of the config struct fails with expecting the specific version of config for that microservice.
failed to build *fiber.App: missing dependencies for function "some-path/http".CreateServer (some-path/http/http.go:65): missing type: *http.Config
exit status 1
Minimal example:
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
}
some-service/config/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)
}
some-service/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()
},
})
}
some-path/controllers/some-controller.go
package controllers
import "some-path/config"
func SomeController (config *config.Config) {
// do stuff
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您缺少
*http.Config
对象,创建一个返回该对象的函数,例如NewConfig()
然后更改您的
provideOptions()
,也许是这样的:You're missing
*http.Config
object, create a function that return that object, e.g.NewConfig()
then change your
provideOptions()
, maybe like this:我参加聚会迟到了,但我最近遇到了同样的情况。我认为您正在寻找类似 将结构转换为Fx 文档中的接口。
另一种方法是指示 Fx 使用接口代替结构,方法是在选项中
Provide
此func
,如下所示I'm late to the party but I recently came across the same situation. I think you are looking for something like casting struct to an interface from the Fx documentation.
An alternate way to do this is instruct Fx to use the interface in place of the struct is by
Provide
ing thisfunc
in your options as shown below