Open oakad opened 5 years ago
Hi @oakad, thanks for getting in touch.
It took me a little bit to digest this issue and understand what is the actual problem you are trying to solve. Configuration bootstrapping in particular is a tricky problem, we have encountered that from time to time but have been able to work around it.
Are there some more concrete examples that you can provide on what situations force you to pass objects from one application graph into the next, or is it only in configuration driven cases?
I'm sorry for being lazy and not providing the actual application example. Here it is, below.
As you can see, I'm trying to run an fx.App
from within another fx.App
. I need to pass some parameters from the outer app to the nested app via the makeNested
constructor. It works pretty well, as long as number of parameters being passed is not too big and can be specified directly in the Go func declaration (pt
struct type in the example). However, in the real app, the number of parameters are big and labels are requires, hence the need for in-out parameter structs: the "provide" of the outer fx.App
passes an "in" parameter pack to the makeNested
constructor, but the forwarding function inside the makeNested
constructor proper is expected to return an "out" parameter pack, making the "pt" struct a good candidate for conversion into an "in/out" parameter pack.
package main
import (
"fmt"
"go.uber.org/fx"
)
type pt struct {
tag string
}
type nested *fx.App
func makeNested(lc fx.Lifecycle, param pt) nested {
n := fx.New(
fx.Provide(
func() pt {
return param
},
),
fx.Invoke(func (param pt) {
fmt.Println(param)
}),
)
lc.Append(fx.Hook {
OnStart: n.Start,
OnStop: n.Stop,
})
return n
}
func main() {
fx.New(
fx.Provide(
func() pt {
return pt{
tag: "Aaaa!",
}
},
makeNested,
),
fx.Invoke(func (n nested) {}),
).Run()
}
Sometimes, it is desirable to have a nested fx.App instance. For example, in applications with complex configuration, it makes sense to have an initial start-up sequence which will construct a configuration dependent start up sequence (a nested fx.App) and will execute that nested sequence as a dependency.
To forward the state information from outer to inner fx.App, something like an "In/Out" parameter pack will be exceptionally handy:
Unfortunately, it would not work with the current version of FX:
This results in a necessity to use an unfortunate boilerplate, in order to forward the products of the outer fx.App instance to the nested one:
I hope this illustrates the utility of "In/Out" parameter packs.