-
Notifications
You must be signed in to change notification settings - Fork 291
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fx.Decorate
not working w/ value groups
#1104
Comments
Hey, thanks for reporting this. I've made a slightly simpler repro on the playground: https://go.dev/play/p/GtqaH27ek0N This seems to be some weird edge case issue with the combination of value groups + decorators + modules/scoping. I'm going to continue investigating, but for now I wanted to report that, other than not using value groups or modules, one workaround I found is to add the Will keep you updated. |
We call simple providers with their original scope: `err := n.Call(n.OrigScope())` (https://github.com/uber-go/dig/blob/master/param.go#L287) This allows decorators to be applied even if the constructor is exported via `dig.Export(true)` However, we call value group value providers with whatever scope we found them in: ``` for _, c := range c.storesToRoot() { providers := c.getGroupProviders(pt.Group, pt.Type.Elem()) // ... for _, n := range providers { if err := n.Call(c); err != nil { /* ... */ } } } ``` This has the consequence of causing exported value group value providers within a module to not be able to be decorated by decorators within the same module, when using `dig.Export(true)`. Since we use `dig.Export(true)` by default in Fx, this is the default behavior for value group providers, see uber-go/fx#1104 This commit changes `callGroupProviders` to use the value group provider's original scope as well, and adds a test to verify the behavior is fixed.
We call simple providers with their original scope: `err := n.Call(n.OrigScope())` (Ref: https://github.com/uber-go/dig/blob/master/param.go#L287) This allows decorators to be applied even if the constructor is exported via `dig.Export(true)` However, we call value group value providers with whatever scope we found them in: ``` for _, c := range c.storesToRoot() { providers := c.getGroupProviders(pt.Group, pt.Type.Elem()) // ... for _, n := range providers { if err := n.Call(c); err != nil { /* ... */ } } } ``` (Ref: https://github.com/uber-go/dig/blob/master/param.go#L609) This has the consequence of causing exported value group value providers within a module to not be able to be decorated by decorators within the same module, when using `dig.Export(true)`. Since we use `dig.Export(true)` by default in Fx, this is the default behavior for value group providers, see uber-go/fx#1104 This commit changes `callGroupProviders` to use the value group provider's original scope as well, and adds a test to verify the behavior is fixed.
We call simple providers with their original scope. (Ref: https://github.com/uber-go/dig/blob/master/param.go#L287) This allows decorators to be applied even if the constructor is exported via `dig.Export(true)`. However, we call value group value providers with whatever scope we found them in: (Ref: https://github.com/uber-go/dig/blob/master/param.go#L609) This has the consequence of causing exported value group value providers within a module to not be able to be decorated by decorators within the same module, when using `dig.Export(true)`, unlike their simple provider counterpart. For example (playground link: https://go.dev/play/p/R2uqaTvT57P): ```go type Foo struct{} type FooResults struct { dig.Out Foo Foo `group:"foos"` } func NewFoo(s string) FooResults { fmt.Printf("String in NewFoo: %q\n", s) return FooResults{ Foo: Foo{}, } } type Bar struct{} func NewBar(s string) Bar { fmt.Printf("String in NewBar: %q\n", s) return Bar{} } type UseFooAndBarParams struct { dig.In Foos []Foo `group:"foos"` Bar Bar } func UseFooAndBar(UseFooAndBarParams) {} func main() { c := dig.New() c.Provide(func() string { return "base" }) child := c.Scope("child") child.Decorate(func(s string) string { return s + "-decorated" }) child.Provide(NewFoo, dig.Export(true)) child.Provide(NewBar, dig.Export(true)) } // Output: // String in NewFoo: "base" // String in NewBar: "base-decorated" ``` Since we use `dig.Export(true)` by default in Fx, this is the default behavior for value group providers, see uber-go/fx#1104 This commit changes `callGroupProviders` to use the value group provider's original scope as well, and adds a test to verify the behavior is fixed.
We call simple providers with their original scope. (Ref: https://github.com/uber-go/dig/blob/master/param.go#L287) This allows decorators to be applied even if the constructor is exported via `dig.Export(true)`. However, we call value group value providers with whatever scope we found them in: (Ref: https://github.com/uber-go/dig/blob/master/param.go#L609) This has the consequence of causing exported value group value providers within a module to not be able to be decorated by decorators within the same module, when using `dig.Export(true)`, unlike their simple provider counterpart. For example (playground link: https://go.dev/play/p/R2uqaTvT57P): ```go type Foo struct{} type FooResults struct { dig.Out Foo Foo `group:"foos"` } func NewFoo(s string) FooResults { fmt.Printf("String in NewFoo: %q\n", s) return FooResults{ Foo: Foo{}, } } type Bar struct{} func NewBar(s string) Bar { fmt.Printf("String in NewBar: %q\n", s) return Bar{} } type UseFooAndBarParams struct { dig.In Foos []Foo `group:"foos"` Bar Bar } func UseFooAndBar(UseFooAndBarParams) {} func main() { c := dig.New() c.Provide(func() string { return "base" }) child := c.Scope("child") child.Decorate(func(s string) string { return s + "-decorated" }) child.Provide(NewFoo, dig.Export(true)) child.Provide(NewBar, dig.Export(true)) } // Output: // String in NewFoo: "base" // String in NewBar: "base-decorated" ``` Since we use `dig.Export(true)` by default in Fx, this is the default behavior for value group providers, see uber-go/fx#1104 This commit changes `callGroupProviders` to use the value group provider's original scope as well, and adds a test to verify the behavior is fixed.
I verified this change in Dig fixes your repro: uber-go/dig#393. |
Sure thing, thanks @JacobOaks for fixing that so quickly! |
We call simple providers with their original scope. (Ref: https://github.com/uber-go/dig/blob/master/param.go#L287) This allows decorators to be applied even if the constructor is exported via `dig.Export(true)`. However, we call value group value providers with whatever scope we found them in: (Ref: https://github.com/uber-go/dig/blob/master/param.go#L609) This has the consequence of causing exported value group value providers within a module to not be able to be decorated by decorators within the same module, when using `dig.Export(true)`, unlike their simple provider counterpart. For example (playground link: https://go.dev/play/p/R2uqaTvT57P): ```go type Foo struct{} type FooResults struct { dig.Out Foo Foo `group:"foos"` } func NewFoo(s string) FooResults { fmt.Printf("String in NewFoo: %q\n", s) return FooResults{ Foo: Foo{}, } } type Bar struct{} func NewBar(s string) Bar { fmt.Printf("String in NewBar: %q\n", s) return Bar{} } type UseFooAndBarParams struct { dig.In Foos []Foo `group:"foos"` Bar Bar } func UseFooAndBar(UseFooAndBarParams) {} func main() { c := dig.New() c.Provide(func() string { return "base" }) child := c.Scope("child") child.Decorate(func(s string) string { return s + "-decorated" }) child.Provide(NewFoo, dig.Export(true)) child.Provide(NewBar, dig.Export(true)) } // Output: // String in NewFoo: "base" // String in NewBar: "base-decorated" ``` Since we use `dig.Export(true)` by default in Fx, this is the default behavior for value group providers, see uber-go/fx#1104 This commit changes `callGroupProviders` to use the value group provider's original scope as well, and adds a test to verify the behavior is fixed.
This upgrades Fx to use the latest Dig version 1.17.1, which contains a bug fix that would solve issues uber-go#1104 and uber-go#1137 (uber-go/dig#393).
This upgrades Fx to use the latest Dig version 1.17.1, which contains a bug fix that would solve issues #1104 and #1137 (uber-go/dig#393).
Describe the bug
When using
fx.Decorate
with value groups, the decorated value (here:zap.Logger
) is not supplied to the constructors (here:NewDummyHandler
) which feed the values.However, the decorator is fed to the other constructor in the group,
NewMyService
, which has no dependents.This issue becomes evident in the logs below. As both the
NewMyService
as well as theNewDummyHandler
constructors are provided within the same module, I expect them to both be fed with the same, decorated logger.I expect the logs to look sth like the following. I reduced the output only to the relevant fields.
However, this is the actual, faulty output, again only the relevant fields:
In the second line, I expect the
logger
field to bemy_service.dummy
, however, the decorated logger seems to not be fed.I don't know what's the cause, probably it's a race (don't know if registring happens in parallel), or if the dependency resolution is faulty, or if it's even expected.
Edit: Probably a dig issue, don't know if I should cross-post the issue there.
Full logs
To Reproduce
go run main.go
main.go
Additional context
Using the newest versions of both dependencies.
Dependency graph
The text was updated successfully, but these errors were encountered: