-
Notifications
You must be signed in to change notification settings - Fork 290
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
Register dispatcher in the default dig graph #304
Conversation
@alsamylkin, thanks for your PR! By analyzing the history of the files in this pull request, we identified @Lupie, @sectioneight and @shawnburke to be potential reviewers. |
doc.go
Outdated
// | ||
// • Logging backed by the zap logger |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wat
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
modules/rpc/yarpc.go
Outdated
@@ -49,6 +50,7 @@ type YARPCModule struct { | |||
log ulog.Log | |||
stateMu sync.RWMutex | |||
isRunning bool | |||
di dig.Graph |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm sure you had your reasons, but I don't know if it's the right thing to attach di object to the YARPC module. Can we think of alternative approaches? Is this purely to make testing easier?
Wouldn't it make testing the handlers difficult, as you'd have to either:
a. Rely on the assumption that we fall back onto the default graph
b. Pass around the reference to the module
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not just use one global graph for UberFx? Makes things much simpler.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Short answer because of snowflakes and tests: it is much easier to write tests with custom graphs, especially when/if yarpc team will add an in memory transport.
Also, I was able to remove di from the struct. Wrote a long rant, why it is hard and then hit an eureka moment..
dig/doc.go
Outdated
@@ -20,7 +20,7 @@ | |||
|
|||
// Package dig is the Dependency Injection Graph. | |||
// | |||
// Package dig provides a fairly opinionated way of resolving object dependencies. | |||
// package dig provides an opinionated way of resolving object dependencies. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rant alert :P I think we overuse the word opinionated, I don't see dig as opinionated particularly. Each type of DI provides a different way of resolving dependencies that's all.
Why not "Dig resolves dependencies and provides users with an instantiated object when requested"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was picked by me randomly, here is the Glib's fix:
https://github.com/uber-go/fx/pull/305/files
dig/doc.go
Outdated
@@ -20,7 +20,7 @@ | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing README files?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, my bad. We have been forgetting doc.go in commits :)
doc.go
Outdated
@@ -27,19 +27,28 @@ | |||
// | |||
// Status | |||
// | |||
// Alpha. Expect minor API changes and bug fixes. (Beta release coming soon) | |||
// Beta. Expect minor API changes and bug fixes. See our changelog (CHANGELOG.md)for more. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should not show up as a change, pull latest changes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did :)
doc.go
Outdated
// | ||
// • Logging backed by the zap logger |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Likewise, there are no changes to this file from this PR. It should go away when you pull changes.
modules/rpc/yarpc_options.go
Outdated
} | ||
|
||
// Intentionally panic if someone adds non-graph to Items. | ||
return g.(dig.Graph) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should you call panic explicitly here? It seems kinda random to force a type assertion panic.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, how an explicit panic will be better than a regular one? It will provide all the types needed:
panic: interface conversion: interface is *dig.graph, not string
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I misread this earlier. Ignore the previous comment.
Changes Unknown when pulling a3d1048 on diDispatcher into ** on master**. |
Changes Unknown when pulling 8bc5fb6 on diDispatcher into ** on master**. |
Changes Unknown when pulling 8bc5fb6 on diDispatcher into ** on master**. |
Changes Unknown when pulling 00f640e on diDispatcher into ** on master**. |
modules/rpc/yarpc_options.go
Outdated
@@ -71,3 +73,20 @@ func onewayInboundMiddlewareFromCreateInfo(mci service.ModuleCreateInfo) []middl | |||
// Intentionally panic if programmer adds non-middleware slice to the data | |||
return items.([]middleware.OnewayInbound) | |||
} | |||
|
|||
func withGraph(graph dig.Graph) modules.Option { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wait a minute. Why is the graph passed as an object? I thought the whole point of having DI is to perform dependency injection and not pass around as a dependency baggage. These objects should just be access d as 'dig.Resolve()'. Otherwise Im having hard time understanding the use of graph vs passing a struct or an interface map.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This.
We need to be really careful about how users are meant to use this.
If we set users up so that they inject the graph into their objects, then we've messed up - the graph isn't supposed to leave main.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@glibsm
Totally agree and we shouldn't use it as an object in fx
as well. I believe this is a situation where global graph is required and should be restricted to be used only within DIG. That way we can have sane dig.Resolve, dig.Register APIs and restrict baggage passing use cases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've added some thoughts to the dig issue on idiomatic usage. #285
I think it might be better to start out with more constrained usage patterns until we get more familiar with dig.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a private option to a constructor for testing.
What you are proposing @anup is to have a graph to be a global dump of all objects, so we essentially left with the same globals as before(actually worse: we added an extra dependency). This is worse for testing, hard to have multiple objects of the same type, etc
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand how it is worst for testing. It might be easier to test here by passing graph, but then how do you test DI outside fx? There may be more work involved in setting up DI for test, but it will at least be transparent.
The graph is a dump of object in either case, but right now we are exposing it to test passing it around. IMHO dig users should not be aware of the graph.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because you can't run tests in parallel, global graph...
Not only this, but we can have multiple dispatchers if we really want and "know what we are doing" :)
I am confused about "test DI outside fx", why do we care in this module about it? We take it as an interface..
Dig users should be aware of graph, otherwise it can be misused.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Synced offline and decided to use a global dig graph and add ability to run tests in parallel through dig, not a local field.
Changes Unknown when pulling 6270af9 on diDispatcher into ** on master**. |
@@ -74,6 +76,11 @@ modules: | |||
|
|||
testInitRunModule(t, goofy[0], mci) | |||
testInitRunModule(t, gopher[0], mci) | |||
|
|||
// Dispatcher must be resolved in the default graph |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does FX need a default graph at all? Why not just instantiate 1 graph when FX is instantiated?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, it is about what graph services are going to use to resolve a dispatcher.
From the thread above we decided to use a default graph and not pass it as a parameter, until we find a better way to do it with dig.
// Try to resolve a controller first | ||
// TODO(alsam) use dig options when available, because we can overwrite the controller in case of multiple | ||
// modules registering a controller. | ||
if err := dig.Resolve(&module.controller); err != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm confused by the term controller here... what exactly is it's responsibility?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There can be multiple modules that can can use YARPC, dispatcherController combines their configs in one and creates a single dispatcher, that a service will use.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we log this err here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, because it can be a valid error: no one registered a controller, and this is what we are going to do in the next line.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor nits to resolve. Also can you update the title before merge?
modules/rpc/yarpc_options.go
Outdated
@@ -29,6 +29,7 @@ import ( | |||
const ( | |||
_interceptorKey = "yarpcUnaryInboundMiddleware" | |||
_onewayInterceptorKey = "yarpcOnewayInboundMiddleware" | |||
_graphInterceptorKey = "yarpcDIGraph" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You don't need this now.
// Try to resolve a controller first | ||
// TODO(alsam) use dig options when available, because we can overwrite the controller in case of multiple | ||
// modules registering a controller. | ||
if err := dig.Resolve(&module.controller); err != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we log this err here?
modules/rpc/yarpc_test.go
Outdated
@@ -25,6 +25,7 @@ import ( | |||
|
|||
"go.uber.org/fx/service" | |||
|
|||
"fmt" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fmt
should be with stdlib imports
modules/rpc/thrift_test.go
Outdated
@@ -30,6 +30,8 @@ import ( | |||
|
|||
"github.com/stretchr/testify/assert" | |||
"github.com/stretchr/testify/require" | |||
"go.uber.org/fx/dig" | |||
"go.uber.org/yarpc" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: arrange imports.
Changes Unknown when pulling 2619746 on diDispatcher into ** on master**. |
Use DIG to store the YAPRC dispatcher.
Right now people are confused about rpc.Dispatcher(), which returns you a dispatcher only if service is started and testing handlers becomes much harder. Proposed solution is to inject it in the default dig graph.