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

Register dispatcher in the default dig graph #304

Merged
8 commits merged into from
Feb 22, 2017
Merged

Register dispatcher in the default dig graph #304

8 commits merged into from
Feb 22, 2017

Conversation

ghost
Copy link

@ghost ghost commented Feb 21, 2017

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.

@mention-bot
Copy link

@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
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wat

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image

Looks like file diff shows the wrong symbol, but the conversation view is fine :/

@coveralls
Copy link

Coverage Status

Coverage decreased (-0.3%) to 91.748% when pulling a402a70 on diDispatcher into 175cddf on master.

@@ -49,6 +50,7 @@ type YARPCModule struct {
log ulog.Log
stateMu sync.RWMutex
isRunning bool
di dig.Graph
Copy link
Collaborator

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

Copy link
Contributor

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.

Copy link
Author

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.
Copy link
Contributor

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"

Copy link
Author

@ghost ghost Feb 21, 2017

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 @@

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing README files?

Copy link
Contributor

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.
Copy link
Contributor

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.

Copy link
Author

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
Copy link
Contributor

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.

}

// Intentionally panic if someone adds non-graph to Items.
return g.(dig.Graph)
Copy link
Contributor

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.

Copy link
Author

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

Copy link
Contributor

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.

@coveralls
Copy link

Coverage Status

Changes Unknown when pulling a3d1048 on diDispatcher into ** on master**.

@coveralls
Copy link

Coverage Status

Changes Unknown when pulling 8bc5fb6 on diDispatcher into ** on master**.

@coveralls
Copy link

Coverage Status

Changes Unknown when pulling 8bc5fb6 on diDispatcher into ** on master**.

@coveralls
Copy link

Coverage Status

Changes Unknown when pulling 00f640e on diDispatcher into ** on master**.

@@ -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 {
Copy link
Contributor

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.

Copy link
Contributor

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.

Copy link
Contributor

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.

Copy link
Contributor

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.

Copy link
Author

@ghost ghost Feb 21, 2017

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

Copy link
Contributor

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.

Copy link
Author

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.

Copy link
Author

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.

@coveralls
Copy link

Coverage Status

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
Copy link
Contributor

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?

Copy link
Author

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 {
Copy link
Contributor

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?

Copy link
Author

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.

Copy link
Contributor

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?

Copy link
Author

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.

Copy link
Contributor

@anuptalwalkar anuptalwalkar left a 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?

@@ -29,6 +29,7 @@ import (
const (
_interceptorKey = "yarpcUnaryInboundMiddleware"
_onewayInterceptorKey = "yarpcOnewayInboundMiddleware"
_graphInterceptorKey = "yarpcDIGraph"
Copy link
Contributor

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 {
Copy link
Contributor

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?

@@ -25,6 +25,7 @@ import (

"go.uber.org/fx/service"

"fmt"
Copy link
Contributor

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

@@ -30,6 +30,8 @@ import (

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/fx/dig"
"go.uber.org/yarpc"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: arrange imports.

@coveralls
Copy link

Coverage Status

Changes Unknown when pulling 2619746 on diDispatcher into ** on master**.

@ghost ghost changed the title DI dispatcher Register dispatcher in the default dig graph Feb 22, 2017
@ghost ghost merged commit b897b67 into master Feb 22, 2017
@ghost ghost deleted the diDispatcher branch February 22, 2017 01:11
This pull request was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

7 participants