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

Consul based service discovery #202

Merged
merged 9 commits into from
Jun 10, 2018

Conversation

mlosiewicz-pl
Copy link
Contributor

Fixes #198

# Set the following in your application.conf if you want to use this discovery mechanism:
# impl = akka-consul

# configured the akka-consul provider
Copy link
Member

Choose a reason for hiding this comment

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

configured => configure

@mlosiewicz-pl
Copy link
Contributor Author

Does anyone have any idea how to fix:

[error] (akka-discovery-aws-api-async/compile:compileIncremental) scala.reflect.internal.FatalError: Error accessing /home/travis/.ivy2/cache/org.apache.httpcomponents/httpcore/jars/httpcore-4.4.7.jar

in travis CI?

@raboof
Copy link
Member

raboof commented May 17, 2018

That seems like some sort of infra problem - I restarted the build.

@ktoso
Copy link
Member

ktoso commented May 20, 2018

Thanks a lot, I'll review in depth on monday :-)

@ktoso
Copy link
Member

ktoso commented May 24, 2018

Well, 5 days late but reviewing now;
We're releasing 0.14 now, though this will be able to be released in an ad-hoc release whenever it is ready btw :)

Copy link
Member

@ktoso ktoso left a comment

Choose a reason for hiding this comment

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

Lookin good! Some comments in line and two general ones I'd like to ask:

  • we need some docs about this, could you add a note how one would use this in the discovery.md file under it's own section? We likely will refactor the docs a bit in the future but a small note in there would be good already :-)
  • Since this assumes that apps register in consul, it also means that we need the "register myself in consul" side right? This is I think the first instance of such integration we have here in akka-management so let's make sure we set a good example. It seems to me that such application on startup should write it's keys to consul- so others will find it. Could we / should we add such register() method to the discovery class there and show how to use it? I think it's pretty powerful if we then make it a general style, so regardless if one uses zk or consul or something else the style would be the same (but that's for later).

@@ -1,6 +1,6 @@
enablePlugins(JavaAppPackaging)

packageName in Universal := "app" // should produce app.zip
com.typesafe.sbt.SbtNativePackager.autoImport.packageName in Universal := "app" // should produce app.zip
Copy link
Member

Choose a reason for hiding this comment

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

was this needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

My sbt was complaining about, but it's probably a local issue.

@@ -0,0 +1,20 @@
######################################################
# Akka Service Discovery Consul Config #
######################################################
Copy link
Member

Choose a reason for hiding this comment

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

nitpick about the # position ;-)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed

consul-host = "127.0.0.1"
consul-port = 8500

application-name-tag-prefix = "system:"
Copy link
Member

Choose a reason for hiding this comment

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

Could you add a small comment above each of the keys what it's about?

Copy link
Member

Choose a reason for hiding this comment

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

So here we would have to explain that we expect values to be present under "system:name-of-my-actor-system" right?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added

Consul.builder().withHostAndPort(HostAndPort.fromParts(settings.consulHost, settings.consulPort)).build()

override def lookup(name: String, resolveTimeout: FiniteDuration): Future[SimpleServiceDiscovery.Resolved] = {
import system.dispatcher
Copy link
Member

Choose a reason for hiding this comment

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

we try to use implicit val ec = system.dispatchet everywhere for safety -- the import if executed in a future technically could reach a null (rarely, and only during system shutdown etc etc, but we try to use the val anyway)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed


private lazy val settings = ConsulSettings.get(system)
private lazy val consul =
Consul.builder().withHostAndPort(HostAndPort.fromParts(settings.consulHost, settings.consulPort)).build()
Copy link
Member

Choose a reason for hiding this comment

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

do they have to be lazy?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

nope,

override def beforeAll(): Unit = {
super.beforeAll()
consul = ConsulStarterBuilder.consulStarter().withHttpPort(8500).build().start()
}
Copy link
Member

Choose a reason for hiding this comment

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

please move the beforeAll above the tests (right next to the var)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

it works without var


override def beforeAll(): Unit = {
super.beforeAll()
consul = ConsulStarterBuilder.consulStarter().withHttpPort(8500).build().start()
Copy link
Member

Choose a reason for hiding this comment

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

seems there's no reason to keep it a var, can we make it a val and innit in constructor?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

Seq(
"com.orbitz.consul" % "consul-client" % "1.1.2",
"com.pszymczyk.consul" % "embedded-consul" % "1.0.2" % "test"
)
Copy link
Member

Choose a reason for hiding this comment

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

Please add a comment with the license next to each of those lines, we have to make sure they are apache compatible (i.e. no GPL code)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added

ResolvedTarget(catalogService.getServiceAddress, Some(port.getOrElse(catalogService.getServicePort)))
}

private val getServicesWithTags = ((callback: ConsulResponseCallback[util.Map[String, util.List[String]]]) =>
Copy link
Member

Choose a reason for hiding this comment

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

could this be a normal method instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

implicit class ConsulResponseFutureDecorator[T](f: ConsulResponseCallback[T] => Unit) {
def asFuture: Future[ConsulResponse[T]] = {
val callback = new ConsulResponseFutureCallback[T]
f(callback)
Copy link
Member

Choose a reason for hiding this comment

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

could f throw? Let's make sure that then the Future is failed rather than the asFuture throwing

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think I did what you asked for, but please take another look

@mlosiewicz-pl
Copy link
Contributor Author

About the registration method - I assume that most of the people doing this already have something in place like ConstructR and have a way of registering services in Consul ( for example if you use Nomad then that part is done for you ) so I would advise against adding a method for registration. The tags assigned to services are not key-value pairs but a set of strings, that's why I need prefixes. Also if we add a method for registration in this case then I would have to make sure that what I register is properly handled by everything set up by consul-template (it is common to set up load balancers based on services in consul) so that there is no duplication. Consul template is also the reason I added the port for akka-management, I don't want it to be accessible through load balancer.

I based the decisions on implementation on an actual production running service and it worked in my case (I mean, I deployed it on prod already ;) to check if it actually work) but in other cases it might not be accurate, but the generic approach with tags should work most of the times.

I will add the discovery.md as soon as I find some spare time and write it all down.

@ktoso
Copy link
Member

ktoso commented May 28, 2018

About the registration method - I assume that most of the people doing this already have something in place like ConstructR and have a way of registering services in Consul ( for example if you use Nomad then that part is done for you ) so I would advise against adding a method for registration.

Note that this project replaces ConstructR, which is already in archived mode even: hseeberger/constructr#174

So, no, we can not say that people will have ConstructR or anything similar to it. We also assume deployments which are no-extra-tooling -- plain jars that someone has run somewhere so there should be standard way to register in such registries, even if many people will not use them because some other mechanism performs the registration for them.

@mlosiewicz-pl
Copy link
Contributor Author

I meant that most of the setup for existing application is already done somewhere and since ConstructR does not register the service in Consul there has to be another mechanism in place already. Adding a registration method in my opinion is not easy (you have to create health checks and know what is exposed where in application - you probably have all the information anyway but still a generic solution would be hard to implement) and will be omitted most of the time.

Said that, I agree that this would be a powerful tool and would allow for quick set up of the cluster with low effort and very quickly. While implementing registration in Consul a lot of configuration options would be have to be added, but it's doable.

@ktoso
Copy link
Member

ktoso commented Jun 1, 2018

That's a good summary – I think it's valuable, but we'll see when/if we end up providing it or not.

As for this PR, I would like to merge it but it needs a bit of documentation -- would you be able to add it? Thanks a lot

@mlosiewicz-pl
Copy link
Contributor Author

Sorry, I was quite busy with some other stuff.

I suck at writing documentation so please check it and if it does not make sense I'll try to write it in some other way.

@@ -0,0 +1,36 @@
How to set up Consul based discovery for Akka Cluster
Copy link
Member

Choose a reason for hiding this comment

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

Docs in general are under the docs project :-)
https://github.com/akka/akka-management/blob/master/docs/src/main/paradox/discovery.md
Here no one would see the documentation after all :-)

Would you want to give adjusting it a try and putting in that spot?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oops, I knew something was not right ... will add it there

@ktoso
Copy link
Member

ktoso commented Jun 10, 2018

Thanks! It's a good start :) I'll merge and we'll see what feedback we get. I'll also want to mark it somehow as community contriubted / "not supported" or something similar until we're confident in it... hope that's fine. Exact wording for these things we'll figure out during this week (we got a team meeting about it :))

@ktoso ktoso merged commit d267ecf into akka:master Jun 10, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants