Application fails to start with fx.Annotate + fx.As + fx.In + fx.Out #924
-
Describe the bug I've tried to use To overcome this - I've used fx.ParamTags, but from what I read from the documentation - it should be working both ways. fx.Annotate(
CreateGreaterWorks,
fx.ParamTags(`name:"helloTo"`),
fx.As(new(Greater))), To Reproduce
package main
import (
"context"
"fmt"
"go.uber.org/fx"
"time"
)
type Greater interface {
SayHello()
}
type ConcreteGreater struct {
helloTo string
}
func (c ConcreteGreater) SayHello() {
fmt.Printf("Hello %s", c.helloTo)
}
type Params struct {
fx.In
HelloTo string `name:"helloTo"`
}
func CreateGreater(params Params) ConcreteGreater {
return ConcreteGreater{helloTo: params.HelloTo}
}
func CreateGreaterWorks(helloTo string) ConcreteGreater {
return ConcreteGreater{helloTo: helloTo}
}
type OutParams struct {
fx.Out
HelloTo string `name:"helloTo"`
}
func NewParams() OutParams {
return OutParams{HelloTo: "world"}
}
func main() {
appWorks := fx.New(
fx.Provide(
NewParams,
fx.Annotate(
CreateGreaterWorks,
fx.ParamTags(`name:"helloTo"`),
fx.As(new(Greater))),
),
fx.Invoke(func(greater Greater) { greater.SayHello() }),
)
if err := appWorks.Start(context.Background()); err != nil {
panic("failed to start application")
}
defer appWorks.Stop(context.Background())
fmt.Printf("Started application with ParamTags")
time.Sleep(time.Second * 3)
appWorksWithoutInterface := fx.New(
fx.Provide(
NewParams,
CreateGreater,
),
fx.Invoke(func(greater ConcreteGreater) { greater.SayHello() }),
)
if err := appWorksWithoutInterface.Start(context.Background()); err != nil {
panic("failed to application with fx.In params")
}
defer appWorksWithoutInterface.Stop(context.Background())
fmt.Printf("Started application with fx.In and fx.Out without interface")
time.Sleep(time.Second * 3)
appFail := fx.New(
fx.Provide(
NewParams,
fx.Annotate(CreateGreater, fx.As(new(Greater))),
),
fx.Invoke(func(greater Greater) { greater.SayHello() }),
)
if err := appFail.Start(context.Background()); err != nil {
panic("failed to application with fx.In + fx.Out params with interface")
}
defer appFail.Stop(context.Background())
} Expected behavior Additional context |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments
-
Hi @noam-ma-ma, thanks for reach out! It seems like the error you're running into is the actual expected behavior of fx. |
Beta Was this translation helpful? Give feedback.
-
I too encountered this issue where For example, consider the case where I have a constructor that returns a concrete type instead of an interface (as is the best practice in golang), and I want to use
I can understand why this is failing, due to the way |
Beta Was this translation helpful? Give feedback.
-
Sorry if this behavior was unexpected. I thought the documentation is pretty clear on what The docs say:
To give you a little bit of background, Annotate() was added so that it can be used instead of Then, Technically, you can still do what type Animal interface { SayHello() string }
type Dog struct { ... }
func (*Dog) SayHello() string { ... }
type Params struct {
fx.In
dogs []Dog `group:"dogs"`
}
type Result struct {
fx.Out
animals []Animal `group:"animals"`
}
fx.Provide(
...
func(p Param) Result {
return Result {
animals: p.Dogs,
}
}, Of course, using Hope that clarifies things, and I will go add some more notes to fx.Annotate's documentation to make this less confusing. |
Beta Was this translation helpful? Give feedback.
Sorry if this behavior was unexpected. I thought the documentation is pretty clear on what
fx.Annotate
does, but I guess it can be confusing. Agreed with @silverspace, this may come across as a surprising behavior if you misunderstand what the documentation meant to say.The docs say:
To give you a little bit of background, Annotate() was added so that it can be used instead of
fx.In
orfx.Out
structs. It was never meant to be a complementary thing.Then,
fx.As
came along, and we added it as part of thefx.Annotate
annotations set.Technically, you can still…