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

Implement a custom HystrixPropertiesStrategy plugin #36

Merged

Conversation

lloydmeta
Copy link
Contributor

Add a custom HystrixPropertiesStrategy implementation where getCommandPropertiesCacheKey is overridden to return null so that HystrixPropertiesFactory will always generate a new HystrixCommandProperties for each new HystrixCommand instantiation.

Add a custom HystrixPropertiesStrategy implementation where getCommandPropertiesCacheKey is overridden
to return null so that HystrixPropertiesFactory will always generate a new HystrixCommandProperties for
each new HystrixCommand instantiation.
@lloydmeta
Copy link
Contributor Author

Should fix #31

Apparently you can only register a strategy once inside a single Java process and
subsequent attempts will cause exceptions to be thrown.

Instead of registering in Global, which, depending on libs/other singletons/w/e,
may already be too late, use the hystrix.plugin.HystrixPropertiesStrategy.implementation
system property and name our class.
@coveralls
Copy link

Coverage Status

Coverage increased (+9.63%) when pulling d77bbde on lloydmeta:feature/cacheless-hystrix-properties-strategy into 4bd7b80 on m3dev:develop.

Might be a good idea to try to make sure CachelessHystrixPropertiesStrategy is used in Global
during onStart if the system property is not set
@coveralls
Copy link

Coverage Status

Coverage increased (+9.3%) when pulling 5153fef on lloydmeta:feature/cacheless-hystrix-properties-strategy into 4bd7b80 on m3dev:develop.

* Resist the temptation to do a HystrixPlugins.getInstance().getPropertiesStrategy first to do
* checking, as that actually also sets the strategy if it isn't already set.
*/
def setHystrixPropertiesStrategy(app: Application): Unit = {
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'm unsure if this is a good idea, or we should just make end-users responsible for always sending the hystrix.plugin.HystrixPropertiesStrategy.implementation system property. Suggestions on other alternatives are welcome.

Copy link
Contributor

Choose a reason for hiding this comment

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

As Octoparts should mostly run out-of-the-box, I'd suggest to not use this hystrix.plugin.HystrixPropertiesStrategy.implementation env variable, and use this new one in any case.

@mauhiz
Copy link
Contributor

mauhiz commented Oct 3, 2014

I woud like to clarify :

  • Will a change in timeout affect currently running commands?
  • Is there an issue on hystrix github or at least some ml thread that recommends using this approach?

@lloydmeta
Copy link
Contributor Author

  • It shouldn't affect currently running commands, as those are instantiated with these properties
  • Javadoc of that method say For example, null can be returned which would cause it to not cache and invoke {@link #getCommandProperties} for each {@link HystrixCommand} instantiation (not recommended) I think the "not recommended" is for performance reasons.

@cb372
Copy link
Contributor

cb372 commented Oct 3, 2014

Also of note is this Hystrix issue: Netflix/Hystrix#34

Looks like they don't want people to be changing properties at runtime.

* generate a new [[HystrixCommandProperties]] for each new [[com.netflix.hystrix.HystrixCommand]] instantiation
*/
class CachelessHystrixPropertiesStrategy extends HystrixPropertiesStrategy {
override def getCommandPropertiesCacheKey(commandKey: HystrixCommandKey, builder: HystrixCommandProperties.Setter): String = null
Copy link
Contributor

Choose a reason for hiding this comment

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

We could build the cache key with commandKey + (a hash of) builder, this should avoid the forewarned performance issues.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah, so maintain our own Map as a cache. Sounds like a good idea.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Reflecting on this now, I guess can get the hashCode of builder, combine it with the commandKey.name in a string and return that.

HystrixPropertiesFactory will be responsible for caching the properties using the returned string anyways.

The disadvantage is that theoretically, the cache could grow out of hand.

@mauhiz @cb372 what do you think?

Copy link
Contributor

Choose a reason for hiding this comment

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

Looks like the least invasive solution so far 👍
On Oct 3, 2014 7:21 PM, "Lloyd" [email protected] wrote:

In app/com/m3/octoparts/hystrix/CachelessHystrixPropertiesStrategy.scala:

@@ -0,0 +1,13 @@
+package com.m3.octoparts.hystrix
+
+import com.netflix.hystrix.{ HystrixCommandKey, HystrixCommandProperties }
+import com.netflix.hystrix.strategy.properties.HystrixPropertiesStrategy
+
+/**

  • * Custom [[HystrixPropertiesStrategy]] implementation where getCommandPropertiesCacheKey is overridden
  • * to return null so that [[com.netflix.hystrix.strategy.properties.HystrixPropertiesFactory]] will always
  • * generate a new [[HystrixCommandProperties]] for each new [[com.netflix.hystrix.HystrixCommand]] instantiation
  • */
    +class CachelessHystrixPropertiesStrategy extends HystrixPropertiesStrategy {
  • override def getCommandPropertiesCacheKey(commandKey: HystrixCommandKey, builder: HystrixCommandProperties.Setter): String = null

Reflecting on this now, I guess can get the hashCode of builder, combine
it with the commandKey.name in a string and return that.

`HystrixPropertiesFactory will be responsible for caching the properties
using the returned string anyways.

The disadvantage is that theoretically, the cache could grow out of hand.

@mauhiz https://github.com/mauhiz @cb372 https://github.com/cb372
what do you think?


Reply to this email directly or view it on GitHub
https://github.com/m3dev/octoparts/pull/36/files#r18388802.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hmm, builder is not a case class and hashCode for the builder is not overridden to be based on the values of the builder, meaning we get new hashCodes for every single newly instantiated builder..

I suppose one way is to manually write a function that grabs values from the builder's accessors (there are at least 20 now), but I don't want to go down that route without exploring other solutions (maybe even just continue returning null)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Nevermind, as of cf0507a, I've changed it to return a string that is a combination of the CommandKey name and the builder JSON string value. Human-readable too now as a bonus.

@lloydmeta
Copy link
Contributor Author

Interesting. I think that PR relates to not allowing injecting different property strategies (via a HystrixCommand) depending on code path, not properties themselves ("property strategy" is not the same as "property"). Since then, the project has changed so that once you set a property strategy, you can no longer change it

Regarding CircuitBreakers, we currently don't allow customisation of circuit breaker settings, so it doesn't directly affect us (yet), and a quick look through the code shows that CircuitBreakers are cached in HystrixCircuitBreaker.java on a per-CommandKey-name basis, so those don't get to change anyways.

I think with Octoparts being essentially something that adds runtime definition support of Hystrix-backed operations, our use-case is slightly different and maybe we might have to ignore some of the recommendations they give. The alternative is we say you can't change Hystrix-related stuff once it's been defined (or at least without restarting the service), which is doesn't seem very friendly.

@@ -14,4 +14,4 @@ before_script:
- psql -c "CREATE USER octoparts_app WITH PASSWORD '';" -U postgres
- psql -c "GRANT ALL PRIVILEGES ON DATABASE octoparts_test to octoparts_app;" -U postgres

script: "sbt coveralls"
script: "sbt coveralls test"
Copy link
Contributor

Choose a reason for hiding this comment

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

didn't coveralls already run tests?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not sure if it was the way we were using it, but the coveralls task is troublesome in that if the compilation fails (like this), the exit status is 0 if the report is uploaded to coveralls properly and the whole build is marked as successful 😆

There may be a more elegant solution to adding test after coveralls but I'm not too sure.

@coveralls
Copy link

Coverage Status

Coverage increased (+9.95%) when pulling e0686f1 on lloydmeta:feature/cacheless-hystrix-properties-strategy into 4bd7b80 on m3dev:develop.

@lloydmeta lloydmeta added this to the 2.2 milestone Oct 7, 2014
mauhiz added a commit that referenced this pull request Oct 8, 2014
…rties-strategy

Implement a custom HystrixPropertiesStrategy plugin
@mauhiz mauhiz merged commit 91cb2e0 into m3dev:develop Oct 8, 2014
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants