Skip to content
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

Add fx.Decorate #833

Merged
merged 8 commits into from Feb 10, 2022
Merged

Add fx.Decorate #833

merged 8 commits into from Feb 10, 2022

Conversation

sywhang
Copy link
Contributor

@sywhang sywhang commented Feb 9, 2022

This adds fx.Decorate, which lets you specify decorators to an fx app. A decorator can take in one or more dependencies that have already been Provided to the app, and produce one or more values that will be used as replacements in the object graph.

For example, suppose there is a simple app like this:

fx.New(
  fx.Provide(func() *Logger {
    return &Logger{Name: "logger"}
  }),
  fx.Invoke(func(l *Logger) {
    fmt.Println(l.Name)
  }),
)

Running this app will print "logger" on the console.

Now let us suppose a decorator was provided:

fx.New(
  fx.Provide(...), // Provide same function as above
  fx.Decorate(func(l *Logger) *Logger {
    return &Logger{Name: "decorated " + l.Name}
  }),
  fx.Invoke(...), // Invoke same function as above
)

The decorator here will take in the provided Logger and replace it with another logger whose Name is decorated logger. The Invoked function is then executed with this replacement value, so running this app will print "decorated logger" on the console.

In terms of implementation, a decorator is represented by the target decorator function and the call stack it was provided from, similar to a provider. module contains a list of decorators that were specified within its scope.

The dig dependency had to be updated to the latest master branch of Dig to ensure the fix for uber-go/dig#316 is in.

Following this PR, there are two additional pieces I will be adding:

  1. An eventing system for fx.Decorate.
  2. fx.Replace, which takes in a value instead of a function to replace a value in the object graph. This is similar to what fx.Supply is to fx.Provide.

This PR along with the two PRs above should make the long-awaited feature of graph modifications in fx finally possible.


Refs #653, #649, #825, uber-go/dig#230, GO-1203, GO-736

@codecov
Copy link

codecov bot commented Feb 9, 2022

Codecov Report

Merging #833 (5a386a0) into master (d2c3431) will increase coverage by 0.04%.
The diff coverage is 100.00%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #833      +/-   ##
==========================================
+ Coverage   98.32%   98.36%   +0.04%     
==========================================
  Files          28       29       +1     
  Lines        1012     1041      +29     
==========================================
+ Hits          995     1024      +29     
  Misses         11       11              
  Partials        6        6              
Impacted Files Coverage Δ
app.go 94.95% <100.00%> (+0.07%) ⬆️
decorate.go 100.00% <100.00%> (ø)
module.go 100.00% <100.00%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update d2c3431...5a386a0. Read the comment docs.

Copy link
Collaborator

@abhinav abhinav left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Surprisingly simple after all of the other changes. No major concerns.
Minus the couple missing untested corner cases, I think this is good to go.

Please get a review from someone else on the team as well.


As an aside: 🎉 🎉 🎉

decorate.go Outdated Show resolved Hide resolved
decorate.go Outdated Show resolved Hide resolved
decorate.go Show resolved Hide resolved
decorate.go Outdated Show resolved Hide resolved
)

app := fxtest.New(t,
testRedis,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is fine as a test, but in the real world, I expect we will not nest "redis" under "testredis".

decorate_test.go Outdated Show resolved Hide resolved
decorate_test.go Outdated
defer app.RequireStart().RequireStop()
})

t.Run("use Decorate in root", func(t *testing.T) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice

Comment on lines +125 to +130
var newC []*Coffee
for _, c := range coffee {
newC = append(newC, &Coffee{
Name: c.Name,
Price: c.Price + 1,
})
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😆

module.go Show resolved Hide resolved
decorate.go Show resolved Hide resolved
decorate.go Outdated Show resolved Hide resolved
decorate_test.go Outdated Show resolved Hide resolved
decorate_test.go Outdated Show resolved Hide resolved
decorate_test.go Outdated Show resolved Hide resolved
decorate_test.go Outdated Show resolved Hide resolved
decorate_test.go Outdated Show resolved Hide resolved
decorate_test.go Outdated Show resolved Hide resolved
@akshayjshah
Copy link
Contributor

Heck yeah! Nice work :)

sywhang and others added 2 commits February 9, 2022 23:39
Co-authored-by: r-hang <42982339+r-hang@users.noreply.github.com>
@sywhang sywhang merged commit 16d4edd into uber-go:master Feb 10, 2022
@sywhang sywhang deleted the fx-decorate branch February 10, 2022 07:50
@Ardagan
Copy link

Ardagan commented Feb 11, 2022

Great work!
Is there any rough estimation when this will end up in released version of fx?

@sywhang
Copy link
Contributor Author

sywhang commented Feb 11, 2022

Thanks @Ardagan! Our current estimate is to ship this by end of the month. We have some more work to do to integrate this with the fxevent package, and add fx.Replace (though there's already a PR out for that - #837). We also need to verify this doesn't break any Go services here at Uber.

After all those have been done, we should be good to go!

@sywhang
Copy link
Contributor Author

sywhang commented Mar 2, 2022

@Ardagan it's been released now: https://github.com/uber-go/fx/releases/tag/v1.17.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants