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

Provide Fx types before user types #1191

Merged
merged 2 commits into from
Apr 19, 2024

Commits on Apr 19, 2024

  1. Provide internal types first

    Consider the following example:
    ```go
    func opts() fx.Option {
            return fx.Options(
                    fx.WithLogger(func(fx.Lifecycle) fxevent.Logger {
                            return &fxevent.ConsoleLogger{ W: os.Stdout }
                    }),
                    fx.Provide(func() string { return "" }),
                    fx.Provide(func() string { return "" }),
            )
    }
    
    func main() {
            fx.New(opts()).Run()
    }
    ```
    
    The relevant issue to surface to the user is that they are double providing
    the same type. However, the actual error message is:
    ```
    [Fx] ERROR              Failed to start: the following errors occurred:
     -  fx.Provide(main.opts.func3()) from:
        main.opts
            /home/user/go/src/scratch/fx_provide_order/main.go:17
        main.main
            /home/user/go/src/scratch/fx_provide_order/main.go:22
        runtime.main
            /opt/go/root/src/runtime/proc.go:271
        Failed: cannot provide function "main".opts.func3
    (/home/user/go/src/scratch/fx_provide_order/main.go:17): cannot provide
    string from [0]: already provided by "main".opts.func2
    (/home/user/go/src/scratch/fx_provide_order/main.go:16)
     -  could not build arguments for function
    "go.uber.org/fx".(*module).constructCustomLogger.func2
            /home/user/go-repos/pkg/mod/go.uber.org/fx@v1.21.0/module.go:292:
        failed to build fxevent.Logger:
        missing dependencies for function "main".opts.func1
            /home/user/go/src/scratch/fx_provide_order/main.go:11:
        missing type:
            - fx.Lifecycle (did you mean to Provide it?)
    ```
    Which contains an additional error related to how the custom logger
    could not be built.
    
    This is because Fx will try to continue to build the custom logger
    in the face of DI failure, theoretically to report issues
    through the right channels. But after an error occurs when
    providing anything, Fx refuses to provide any more types - leading to
    a subsequent error when trying to build this custom logger
    that depends on the `fx.Lifecycle` type.
    
    This is a common issue that can be misleading for new engineers
    debugging their fx apps.
    
    I couldn't find any particular reason why user-provided provides
    are registered before these Fx types, se this PR switches this ordering
    so that custom loggers can still be built if they rely on the Fx types,
    which cleans up the error message:
    ```
    [Fx] ERROR              Failed to start: fx.Provide(main.opts.func3())
    from:
    main.opts
            /home/user/go/src/scratch/fx_provide_order/main.go:17
    main.main
            /home/user/go/src/scratch/fx_provide_order/main.go:22
    runtime.main
            /opt/go/root/src/runtime/proc.go:271
    Failed: cannot provide function "main".opts.func3
    (/home/user/go/src/scratch/fx_provide_order/main.go:17): cannot provide
    string from [0]: already provided by "main".opts.func2
    (/home/user/go/src/scratch/fx_provide_order/main.go:16)
    ```
    JacobOaks committed Apr 19, 2024
    Configuration menu
    Copy the full SHA
    81d3ff8 View commit details
    Browse the repository at this point in the history
  2. fix typo

    JacobOaks committed Apr 19, 2024
    Configuration menu
    Copy the full SHA
    4626474 View commit details
    Browse the repository at this point in the history