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

Migrate Spray caching as akka-http-caching #213 #986

Closed
wants to merge 23 commits into from

Conversation

tomrf1
Copy link
Contributor

@tomrf1 tomrf1 commented Mar 21, 2017

Guided by the discussion here (@ktoso, @ben-manes and @ianclegg) this change migrates the Spray cache and cache directive across to a separate project, akka-http-caching.

This is an almost like-for-like replacement of the spray implementation (including the tests). I've generally left the code the same where possible, but there are some changes:

  1. Whereas spray used ConcurrentLinkedHashMap for LruCache, it now uses caffeine's AsyncLoadingCache.
  2. Removed ascendingKeys from the Cache trait because AsyncLoadingCache doesn't appear to have an equivalent method. I'm also not sure when you'd use it.
  3. Removed implicit ExecutionContext from apply methods because it was only being used for completing the futures, whereas now it simply calls get on the caffeine cache. Does anyone think this will be a problem?
  4. Because AsyncLoadingCache requires a loader on creation, a 'default' loader function must be passed in when creating a LruCache. Calling code can still pass in a separate loading function to apply.
  5. Edit: Changed signature of def remove(key: Any): Option[Future[V]] to def remove(key: Any): Unit, as the value is unlikely to be needed

@lightbend-cla-validator

Hi @tomrf1,

Thank you for your contribution! We really value the time you've taken to put this together.

Before we proceed with reviewing this pull request, please sign the Lightbend Contributors License Agreement:

http://www.lightbend.com/contribute/cla

@akka-ci
Copy link

akka-ci commented Mar 21, 2017

Can one of the repo owners verify this patch?

@ktoso
Copy link
Member

ktoso commented Mar 21, 2017

OK TO TEST

@ktoso
Copy link
Member

ktoso commented Mar 21, 2017

NICE! Looking forward to reviewing :-)
We're doing team meeting and planning these few days so sorry for the delay in reviewing that may happen

@akka-ci akka-ci added validating PR that is currently being validated by Jenkins needs-attention Indicates a PR validation failure (set by CI infrastructure) and removed validating PR that is currently being validated by Jenkins labels Mar 21, 2017
@akka-ci
Copy link

akka-ci commented Mar 21, 2017

Test FAILed.

@ben-manes
Copy link

This looks really nice!

ascendingKeys(n) is a snapshot from coldest to hottest, which mirrors descendingKeySet that goes hottest to coldest. These were added for Cassandra which wanted to save the cache on shutdown for a warm restart. I'm not sure what they were used for by Spray. The equivalent in Caffeine is in Policy.Eviction, hottest(n) and coldest(n). This can be obtained using cache.synchronous().policy().eviction().

Note that Caffeine uses TinyLFU instead of LRU for the eviction algorithm. Your class names with Lru may give the wrong expectations.

The ExecutionContext could be honored if you use get(key, (key, executor) => future). Instead of using the supplied executor, you could use caller's. Alternatively, you could supply the ExecutionContext at creation time as the cache's executor by setting it in the builder.

It hasn't been clear to me whether introducing an AsyncCache would be useful. I'm glad you found the workaround. If there is a general consensus that it would be a good addition then the API was structures to make it seamless. My concern is that users will be inclined to use getIfPresent and put methods instead of the preferred loading methods, e.g. get(key, func).

As a side note, if there is a desire for variable expiration, then that is a feature that we could collaborate on. The design that I've settled on is a hierarchical timer wheel, as shown in this slide deck (slide 10). This is an O(1) algorithm that would allow entries to have different expiration times, e.g. if caching external http resources based on their expiration header.


def apply(key: Any, genValue: () ⇒ Future[V]): Future[V] = store.get(key, toJavaMappingFunction(genValue)).toScala

def remove(key: Any): Option[Future[V]] = Option(store.synchronous().asMap().remove(key)).map(Future.successful)

Choose a reason for hiding this comment

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

When would a caller require the value on a removal? Its rare for a cache, so the penalty of waiting until the underlying future returns might be avoided.

If this is useful, we could look into supplying an asMap() view on the AsyncLoadingCache.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The spray implementation does not use remove, and I can't think why it would be useful to return the value. I had tried to keep the definitions consistent, but it's tempting to change this to:
def remove(key: Any): Unit

Choose a reason for hiding this comment

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

A scan of usages on Github indicate the value is often ignored.

You might argue that this is a simple cache for the common cases, but users with more advanced needs should use Caffeine (or alternatives) directly. That way feature requests are kept at a minimum, as you aren't trying to cater to every edge case.

@akka-ci akka-ci added validating PR that is currently being validated by Jenkins needs-attention Indicates a PR validation failure (set by CI infrastructure) and removed needs-attention Indicates a PR validation failure (set by CI infrastructure) validating PR that is currently being validated by Jenkins labels Mar 21, 2017
@akka-ci
Copy link

akka-ci commented Mar 21, 2017

Test FAILed.

@akka-ci akka-ci added validating PR that is currently being validated by Jenkins needs-attention Indicates a PR validation failure (set by CI infrastructure) and removed needs-attention Indicates a PR validation failure (set by CI infrastructure) validating PR that is currently being validated by Jenkins labels Mar 25, 2017
@akka-ci
Copy link

akka-ci commented Mar 25, 2017

Test FAILed.

Copy link
Member

@jonas jonas left a comment

Choose a reason for hiding this comment

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

LGTM, however it would be nice to also have at least the scaladsl part documented.

For completeness this also needs a Java API but we could deal with that in a separate ticket as long as we mark the API with the Experimental annotation since we cannot guarantee binary compatibility until the Java API is in place.

@@ -0,0 +1,4 @@
import akka._

libraryDependencies ++= Seq(
Copy link
Member

Choose a reason for hiding this comment

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

Please define this in the Compile object in project/Dependencies.scala and add to Dependencies.httpCaching

* a non-zero and finite timeToLive and/or timeToIdle is set or not.
*/
def apply[V](
defaultLoader: Any ⇒ Future[V],
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 formatted with scalariform?

import akka.http.scaladsl.model.headers.CacheDirectives._
import akka.http.scaladsl.server.RouteResult.Rejected

trait CachingDirectives {
Copy link
Member

Choose a reason for hiding this comment

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

Each exposed directives should be documented in a separate page in the docs project and listed in the alphabetically and by-trait pages. The spray cache directives docs look like a good start.

Some minimal documentation introducing caching based on
https://github.com/spray/spray/blob/master/docs/documentation/spray-caching/index.rst would also be great. This would also be a good place to make it clear that using the caching directives requires adding an additional dependency.

@@ -0,0 +1,92 @@
package akka.http.routing.directives
Copy link
Member

Choose a reason for hiding this comment

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

The package for the Scala directives should be akka.http.scaladsl.server.directives

@akka-ci akka-ci added validating PR that is currently being validated by Jenkins and removed needs-attention Indicates a PR validation failure (set by CI infrastructure) labels Mar 26, 2017
@tomrf1
Copy link
Contributor Author

tomrf1 commented Mar 26, 2017

@jonas thanks for the feedback, I've pushed some changes plus docs/examples for the caching directives.
I'm not familiar with the experimental annotation, is this specific to akka?

@akka-ci akka-ci added needs-attention Indicates a PR validation failure (set by CI infrastructure) and removed validating PR that is currently being validated by Jenkins labels Mar 26, 2017
@akka-ci
Copy link

akka-ci commented Mar 26, 2017

Test FAILed.

@akka-ci akka-ci added validating PR that is currently being validated by Jenkins needs-attention Indicates a PR validation failure (set by CI infrastructure) and removed needs-attention Indicates a PR validation failure (set by CI infrastructure) labels Mar 26, 2017
@ktoso ktoso self-assigned this Oct 31, 2017
@ktoso
Copy link
Member

ktoso commented Oct 31, 2017

Attempting to get this merged today, thanks for patiently working on this for such a long time!

@ktoso
Copy link
Member

ktoso commented Oct 31, 2017

PLS BUILD

@akka-ci akka-ci added validating PR that is currently being validated by Jenkins needs-attention Indicates a PR validation failure (set by CI infrastructure) and removed needs-attention Indicates a PR validation failure (set by CI infrastructure) validating PR that is currently being validated by Jenkins labels Oct 31, 2017
@akka-ci
Copy link

akka-ci commented Oct 31, 2017

Test FAILed.

@ktoso
Copy link
Member

ktoso commented Oct 31, 2017

Awesome work @tomrf1!

I believe this is ready to merge and I have some slight follow up changes I'll PR separately. I checked the comments that @jrudolph had and those are addressed as well or I'll do so in the PR I have prepped.

I'll finish figuring out why the build fails with [error] com.lightbend.paradox.markdown.Index$LinkException: Unknown page [low-level-api.md] linked from [java/http/server-side/index.md] etc and merge this PR and do my follow up (prepared already) shortly then.

:shipit:

@jonas
Copy link
Member

jonas commented Oct 31, 2017

It could be #1371

@jonas
Copy link
Member

jonas commented Oct 31, 2017

I started porting the doc here: https://github.com/jonas/akka-http/tree/caching-docs

@ktoso
Copy link
Member

ktoso commented Oct 31, 2017

Yeah it's the symlink that did not get created and blows up the PR now https://github.com/akka/akka-http/pull/1371/files#r147919705
It's not really failing the new docs though, but all of the normal dos files (not the caching ones)... very weird.

@jonas
Copy link
Member

jonas commented Oct 31, 2017

PLS BUILD

@akka-ci akka-ci added validating PR that is currently being validated by Jenkins needs-attention Indicates a PR validation failure (set by CI infrastructure) and removed needs-attention Indicates a PR validation failure (set by CI infrastructure) validating PR that is currently being validated by Jenkins labels Oct 31, 2017
@akka-ci
Copy link

akka-ci commented Oct 31, 2017

Test FAILed.

@ktoso ktoso added reviewed Ready to merge from review perspetive, but awaiting some additional action (e.g. order of merges) and removed reviewed Ready to merge from review perspetive, but awaiting some additional action (e.g. order of merges) labels Nov 1, 2017
@raboof
Copy link
Member

raboof commented Nov 14, 2017

PLS BUILD

@akka-ci akka-ci added validating PR that is currently being validated by Jenkins tested PR that was successfully built and tested by Jenkins and removed needs-attention Indicates a PR validation failure (set by CI infrastructure) validating PR that is currently being validated by Jenkins labels Nov 14, 2017
@akka-ci
Copy link

akka-ci commented Nov 14, 2017

Test PASSed.

@ktoso
Copy link
Member

ktoso commented Nov 15, 2017

@raboof please notice that I continued work on this over in #1503 and that should be merged (very carefully to keep commits), rather than this PR I think

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.

Rather, #1503 should be merged, as I cleaned up some things in it.

@ktoso ktoso closed this Nov 15, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
tested PR that was successfully built and tested by Jenkins
Projects
None yet
Development

Successfully merging this pull request may close these issues.