diff --git a/core/src/main/scala/scalacache/Cache.scala b/core/src/main/scala/scalacache/Cache.scala index f349c60a..1ef1912b 100644 --- a/core/src/main/scala/scalacache/Cache.scala +++ b/core/src/main/scala/scalacache/Cache.scala @@ -29,5 +29,15 @@ trait Cache { */ def remove(key: String): Future[Unit] + /** + * You should call this when you have finished using this Cache. + * (e.g. when your application shuts down. + * + * It will take care of gracefully shutting down the underlying cache client. + * + * Note that you should not try to use this Cache instance after you have called this method. + */ + def close(): Unit + } diff --git a/core/src/test/scala/scalacache/mocks.scala b/core/src/test/scala/scalacache/mocks.scala index d9aea8c7..17b0f1ea 100644 --- a/core/src/test/scala/scalacache/mocks.scala +++ b/core/src/test/scala/scalacache/mocks.scala @@ -8,18 +8,21 @@ class EmptyCache extends Cache { override def get[V](key: String): Future[Option[V]] = Future.successful(None) override def put[V](key: String, value: V, ttl: Option[Duration]) = Future.successful((): Unit) override def remove(key: String) = Future.successful((): Unit) + override def close(): Unit = {} } class FullCache(value: Any) extends Cache { override def get[V](key: String): Future[Option[V]] = Future.successful(Some(value).asInstanceOf[Option[V]]) override def put[V](key: String, value: V, ttl: Option[Duration]) = Future.successful((): Unit) override def remove(key: String) = Future.successful((): Unit) + override def close(): Unit = {} } class FailedFutureReturningCache extends Cache { override def get[V](key: String): Future[Option[V]] = Future.failed(new RuntimeException("failed to read")) override def put[V](key: String, value: V, ttl: Option[Duration]): Future[Unit] = Future.failed(new RuntimeException("failed to write")) override def remove(key: String) = Future.successful((): Unit) + override def close(): Unit = {} } /** @@ -40,6 +43,9 @@ class MockCache extends Cache { def remove(key: String) = Future.successful(mmap.remove(key)) + + def close(): Unit = {} + } /** diff --git a/ehcache/src/main/scala/scalacache/ehcache/EhcacheCache.scala b/ehcache/src/main/scala/scalacache/ehcache/EhcacheCache.scala index f14a3685..eb2b784b 100644 --- a/ehcache/src/main/scala/scalacache/ehcache/EhcacheCache.scala +++ b/ehcache/src/main/scala/scalacache/ehcache/EhcacheCache.scala @@ -53,6 +53,10 @@ class EhcacheCache(underlying: Ehcache) */ override def remove(key: String) = Future.successful(underlying.remove(key)) + override def close(): Unit = { + // Nothing to do + } + } object EhcacheCache { diff --git a/guava/src/main/scala/scalacache/guava/GuavaCache.scala b/guava/src/main/scala/scalacache/guava/GuavaCache.scala index e5237f00..c32f57b1 100644 --- a/guava/src/main/scala/scalacache/guava/GuavaCache.scala +++ b/guava/src/main/scala/scalacache/guava/GuavaCache.scala @@ -62,6 +62,10 @@ class GuavaCache(underlying: GCache[String, Object]) */ override def remove(key: String) = Future.successful(underlying.invalidate(key)) + override def close(): Unit = { + // Nothing to do + } + private def toExpiryTime(ttl: Duration): DateTime = DateTime.now.plusMillis(ttl.toMillis.toInt) } diff --git a/lrumap/src/main/scala/scalacache/lrumap/LruMapCache.scala b/lrumap/src/main/scala/scalacache/lrumap/LruMapCache.scala index f7a1ee1c..a5a18fb5 100644 --- a/lrumap/src/main/scala/scalacache/lrumap/LruMapCache.scala +++ b/lrumap/src/main/scala/scalacache/lrumap/LruMapCache.scala @@ -62,6 +62,10 @@ class LruMapCache(underlying: LruMap[String, Object]) override def remove(key: String): Future[Unit] = Future.successful(underlying.remove(key)) + override def close(): Unit = { + // Nothing to do + } + private def toExpiryTime(ttl: Duration): DateTime = DateTime.now.plusMillis(ttl.toMillis.toInt) } diff --git a/memcached/src/main/scala/scalacache/memcached/MemcachedCache.scala b/memcached/src/main/scala/scalacache/memcached/MemcachedCache.scala index 9d0c21d8..3ab6201a 100644 --- a/memcached/src/main/scala/scalacache/memcached/MemcachedCache.scala +++ b/memcached/src/main/scala/scalacache/memcached/MemcachedCache.scala @@ -71,6 +71,10 @@ class MemcachedCache(client: MemcachedClient, keySanitizer: MemcachedKeySanitize p.future } + override def close(): Unit = { + client.shutdown() + } + } object MemcachedCache { diff --git a/redis/src/main/scala/scalacache/redis/RedisCache.scala b/redis/src/main/scala/scalacache/redis/RedisCache.scala index dc55c94a..6369bad6 100644 --- a/redis/src/main/scala/scalacache/redis/RedisCache.scala +++ b/redis/src/main/scala/scalacache/redis/RedisCache.scala @@ -75,6 +75,10 @@ class RedisCache(jedisPool: JedisPool, override val customClassloader: Option[Cl } } + override def close(): Unit = { + jedisPool.close() + } + private def withJedisClient[T](f: Jedis => T): T = { val jedis = jedisPool.getResource() try {