Sorting within a group of dependencies #886
-
Currently when adding a dependency to a group the order within the group is not guaranteed. How about adding a type Annotated struct {
Name string
Group string
Target interface{}
// Set an order weight for this dependency 0 < X < 100
Weight float32
} OR type result struct {
fx.Out
MyHandler http.Handler `group: "handlers,10.5"`
} Weight range should be within (0,100) |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments
-
Hello, @talgendler, thanks for the proposal. Background: We felt that for cases when ordering mattered, it really mattered. Recommendation: The rough design we went with there is:
So the consumer looks roughly like the following: package foo
type Middleware interface {
// Name specifies the name of the middleware.
// It must be unique in an application.
Name() string
// Wrap applies the middleware on the method.
Wrap(Method) (Method, error)
}
type Config struct {
// List of middleware that should run in-order.
Middleware []string `yaml:"middleware"`
}
var Module = fx.Provide(New)
type Params struct {
fx.In
Config Config
Middlewares []Middleware `group:"myapp"`
}
func New(p Params) (Result, error) {
// Collate middleware by name.
mws := make(map[string]Middleware)
for _, m := range p.Middlewares {
name := m.Name()
if _, ok := mws[name]; ok {
return nil, fmt.Errorf("received middleware %q multiple times", name)
}
mws[name] = m
}
var result []Middleware // ordered list of requested middleware
for _, name := range p.Config.Middleware {
mw, ok := mws[name]
if !ok {
return nil, fmt.Errorf("unknown middleware %q requested in config", name)
}
result = append(result, mw)
}
return applyMiddlewares(..., result)
} Various middleware modules look roughly like this: package retry
const Name = "retry"
var Module = fx.Provide(
fx.Annotated{
Target: New,
Group: "myapp",
},
)
type middleware struct {
// ...
}
func New(...) foo.Middleware {
// ...
}
func (mw *middleware) Name() string {
return Name
}
// ... And finally, the application does something similar: fx.New(
foo.Module,
retry.Module,
config.Module,
logging.Module,
// ...
).Run() Where So the user can do: middlewares: [retry, logging, ratelimit] Hope this helps! |
Beta Was this translation helpful? Give feedback.
-
Thanks that was a great example. |
Beta Was this translation helpful? Give feedback.
Hello, @talgendler, thanks for the proposal.
Sorry, we don't think Dig/Fx should support weight-based value groups.
However, there's a pattern we can recommend instead.
Read on for details.
Background:
Value groups are intended to be used for unordered collections only.
We specifically made that decision when designing the API,
and we intentionally randomize the order in which the value group is filled:
https://github.com/uber-go/dig/blob/173b7b1935ec5ea6b26ebaf0b513658752f58c79/dig.go#L479
We felt that for cases when ordering mattered, it really mattered.
For those cases, it was desirable for the application to have full control on the order.
An API based on weights/z-indexing allows any…