From aa85ee9b5b23e910be6963219a939ecedb1558de Mon Sep 17 00:00:00 2001 From: Abhinav Gupta Date: Fri, 3 Jan 2025 20:03:58 -0800 Subject: [PATCH 1/5] chore(go.mod): bump to go 1.22 (#1255) --- docs/go.mod | 2 +- docs/go.sum | 1 + go.mod | 2 +- go.sum | 5 +++++ internal/e2e/go.mod | 2 +- internal/e2e/go.sum | 1 + 6 files changed, 10 insertions(+), 3 deletions(-) diff --git a/docs/go.mod b/docs/go.mod index ecdce61c6..aefe9f678 100644 --- a/docs/go.mod +++ b/docs/go.mod @@ -1,6 +1,6 @@ module go.uber.org/fx/docs -go 1.20 +go 1.22 require ( github.com/stretchr/testify v1.8.1 diff --git a/docs/go.sum b/docs/go.sum index e1af24cab..63e4d7c0e 100644 --- a/docs/go.sum +++ b/docs/go.sum @@ -13,6 +13,7 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o go.uber.org/dig v1.18.0 h1:imUL1UiY0Mg4bqbFfsRQO5G4CGRBec/ZujWTvSVp3pw= go.uber.org/dig v1.18.0/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE= go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= +go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo= go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= diff --git a/go.mod b/go.mod index e3c9eec51..0ca046c07 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module go.uber.org/fx -go 1.20 +go 1.22 require ( github.com/stretchr/testify v1.8.1 diff --git a/go.sum b/go.sum index b8702a8a8..12eaae730 100644 --- a/go.sum +++ b/go.sum @@ -2,7 +2,9 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -21,11 +23,14 @@ go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN8 go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/e2e/go.mod b/internal/e2e/go.mod index d93ec6606..b3770905c 100644 --- a/internal/e2e/go.mod +++ b/internal/e2e/go.mod @@ -1,6 +1,6 @@ module go.uber.org/fx/internal/e2e -go 1.20 +go 1.22 require ( github.com/stretchr/testify v1.8.2 diff --git a/internal/e2e/go.sum b/internal/e2e/go.sum index 6630a577c..80f7a975c 100644 --- a/internal/e2e/go.sum +++ b/internal/e2e/go.sum @@ -13,6 +13,7 @@ github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o go.uber.org/dig v1.18.0 h1:imUL1UiY0Mg4bqbFfsRQO5G4CGRBec/ZujWTvSVp3pw= go.uber.org/dig v1.18.0/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE= go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= +go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo= go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= From 7eebf3c30827569be4e0f5c3914ad2be5e1d9bbf Mon Sep 17 00:00:00 2001 From: Abhinav Gupta Date: Sat, 4 Jan 2025 08:56:11 -0800 Subject: [PATCH 2/5] doc(App.Run): Clarify exit code (#1254) A user expressed confusion about the exit code of an Fx application that was interrupted with Ctrl-C. Clarify in the documentation that the exit code will be non-zero only if there was a failure, or if Shutdown specifically requested a non-zero exit code. --- app.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/app.go b/app.go index ef3d35a0d..7a0168fc0 100644 --- a/app.go +++ b/app.go @@ -595,6 +595,14 @@ func (app *App) exit(code int) { // All of Run's functionality is implemented in terms of the exported // Start, Done, and Stop methods. Applications with more specialized needs // can use those methods directly instead of relying on Run. +// +// After the application has started, +// it can be shut down by sending a signal or calling [Shutdowner.Shutdown]. +// On successful shutdown, whether initiated by a signal or by the user, +// Run will return to the caller, allowing it to exit cleanly. +// Run will exit with a non-zero status code +// if startup or shutdown operations fail, +// or if the [Shutdowner] supplied a non-zero exit code. func (app *App) Run() { // Historically, we do not os.Exit(0) even though most applications // cede control to Fx with they call app.Run. To avoid a breaking From 928af08adc335d2e47e4e6c3ff2184e77ba26e7a Mon Sep 17 00:00:00 2001 From: Josh Kline Date: Wed, 8 Jan 2025 20:16:38 -0800 Subject: [PATCH 3/5] doc(lifecycle.go): fix examples (#1256) Fix function defined in documentation for `StartHook` and `StopHook` to match the reset of the example. --- lifecycle.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lifecycle.go b/lifecycle.go index 50198488e..98ab25d80 100644 --- a/lifecycle.go +++ b/lifecycle.go @@ -53,7 +53,7 @@ type Hook struct { // StartHook returns a new Hook with start as its [Hook.OnStart] function, // wrapping its signature as needed. For example, given the following function: // -// func myhook() { +// func myfunc() { // fmt.Println("hook called") // } // @@ -86,7 +86,7 @@ func StartHook[T HookFunc](start T) Hook { // StopHook returns a new Hook with stop as its [Hook.OnStop] function, // wrapping its signature as needed. For example, given the following function: // -// func myhook() { +// func myfunc() { // fmt.Println("hook called") // } // From 0ad8a0474d9998aab5e6e76691a650ca54b5c15f Mon Sep 17 00:00:00 2001 From: Abhinav Gupta Date: Thu, 9 Jan 2025 09:59:17 -0800 Subject: [PATCH 4/5] refac: DRY up New, reuse *All methods, delete modules slice (#1258) The pattern we appear to have for Fx operations (Provide, Invoke, etc.) take the form: func (*module) thing(t thing) func (m *module) thingAll() { // perform module-local version of operation for _, t := range m.things { m.thing(t) } // recurse into children for _, m := range m.modules { m.${operation}All() } } This means that the following two are equivalent: // 1 for _, m := range app.modules { m.thingAll() } // 2 app.root.thingAll() Except (2) is DRYer. This cleans up New by relying on root-level `*All` methods instead of manually iterating over modules. Making this change also highlighted that 'app.modules' only ever has one entry: the root module. So we can delete that field from App as well. Finally, this also renames: constructAllCustomLoggers -> installAllEventLoggers constructCustomLogger -> installEventLogger executeInvokes -> invokeAll executeInvoke -> invoke --- app.go | 22 ++++++---------------- module.go | 17 ++++++++--------- 2 files changed, 14 insertions(+), 25 deletions(-) diff --git a/app.go b/app.go index 7a0168fc0..c340e15b7 100644 --- a/app.go +++ b/app.go @@ -304,7 +304,6 @@ type App struct { container *dig.Container root *module - modules []*module // Timeouts used startTimeout time.Duration @@ -446,7 +445,6 @@ func New(opts ...Option) *App { log: logger, trace: []string{fxreflect.CallerStack(1, 2)[0].String()}, } - app.modules = append(app.modules, app.root) for _, opt := range opts { opt.apply(app.root) @@ -475,10 +473,7 @@ func New(opts ...Option) *App { } app.container = dig.New(containerOptions...) - - for _, m := range app.modules { - m.build(app, app.container) - } + app.root.build(app, app.container) // Provide Fx types first to increase the chance a custom logger // can be successfully built in the face of unrelated DI failure. @@ -490,13 +485,10 @@ func New(opts ...Option) *App { }) app.root.provide(provide{Target: app.shutdowner, Stack: frames}) app.root.provide(provide{Target: app.dotGraph, Stack: frames}) + app.root.provideAll() - for _, m := range app.modules { - m.provideAll() - } - - // Run decorators before executing any Invokes -- including the one - // inside constructCustomLogger. + // Run decorators before executing any Invokes + // (including the ones inside installAllEventLoggers). app.err = multierr.Append(app.err, app.root.decorateAll()) // If you are thinking about returning here after provides: do not (just yet)! @@ -504,9 +496,7 @@ func New(opts ...Option) *App { // We'll want to flush them to the logger. // custom app logger will be initialized by the root module. - for _, m := range app.modules { - m.constructAllCustomLoggers() - } + app.root.installAllEventLoggers() // This error might have come from the provide loop above. We've // already flushed to the custom logger, so we can return. @@ -514,7 +504,7 @@ func New(opts ...Option) *App { return app } - if err := app.root.executeInvokes(); err != nil { + if err := app.root.invokeAll(); err != nil { app.err = err if dig.CanVisualizeError(err) { diff --git a/module.go b/module.go index d1986dafd..4615ad46a 100644 --- a/module.go +++ b/module.go @@ -253,11 +253,11 @@ func (m *module) supply(p provide) { } // Constructs custom loggers for all modules in the tree -func (m *module) constructAllCustomLoggers() { +func (m *module) installAllEventLoggers() { if m.logConstructor != nil { if buffer, ok := m.log.(*logBuffer); ok { // default to parent's logger if custom logger constructor fails - if err := m.constructCustomLogger(buffer); err != nil { + if err := m.installEventLogger(buffer); err != nil { m.app.err = multierr.Append(m.app.err, err) m.log = m.fallbackLogger buffer.Connect(m.log) @@ -269,12 +269,11 @@ func (m *module) constructAllCustomLoggers() { } for _, mod := range m.modules { - mod.constructAllCustomLoggers() + mod.installAllEventLoggers() } } -// Mirroring the behavior of app.constructCustomLogger -func (m *module) constructCustomLogger(buffer *logBuffer) (err error) { +func (m *module) installEventLogger(buffer *logBuffer) (err error) { p := m.logConstructor fname := fxreflect.FuncName(p.Target) defer func() { @@ -297,15 +296,15 @@ func (m *module) constructCustomLogger(buffer *logBuffer) (err error) { }) } -func (m *module) executeInvokes() error { +func (m *module) invokeAll() error { for _, m := range m.modules { - if err := m.executeInvokes(); err != nil { + if err := m.invokeAll(); err != nil { return err } } for _, invoke := range m.invokes { - if err := m.executeInvoke(invoke); err != nil { + if err := m.invoke(invoke); err != nil { return err } } @@ -313,7 +312,7 @@ func (m *module) executeInvokes() error { return nil } -func (m *module) executeInvoke(i invoke) (err error) { +func (m *module) invoke(i invoke) (err error) { fnName := fxreflect.FuncName(i.Target) m.log.LogEvent(&fxevent.Invoking{ FunctionName: fnName, From ca61c3dc78a6ac0a5991fafa86546e00b7fcb47a Mon Sep 17 00:00:00 2001 From: Lucas Paiolla Date: Tue, 21 Jan 2025 17:21:26 -0300 Subject: [PATCH 5/5] Fix typo in parameter-objects.md (#1260) --- docs/src/parameter-objects.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/parameter-objects.md b/docs/src/parameter-objects.md index 8e7682ff4..404c6855b 100644 --- a/docs/src/parameter-objects.md +++ b/docs/src/parameter-objects.md @@ -1,6 +1,6 @@ # Parameter Objects -A parameter object is an objects with the sole purpose of carrying parameters +A parameter object is an object with the sole purpose of carrying parameters for a specific function or method. The object is typically defined exclusively for that function,