{"id":224,"date":"2012-07-15T17:39:26","date_gmt":"2012-07-15T21:39:26","guid":{"rendered":"http:\/\/localhost\/wordpress\/?p=224"},"modified":"2013-02-09T10:04:12","modified_gmt":"2013-02-09T15:04:12","slug":"an-auto-updating-caching-system-part-1","status":"publish","type":"post","link":"https:\/\/sourcedelica.com\/blog\/2012\/07\/an-auto-updating-caching-system-part-1\/","title":{"rendered":"An Auto-Updating Caching System &#8211; part 1"},"content":{"rendered":"<p>Imagine you needed to build a caching system in front of a slow backend system with the following requirements:<\/p>\n<ul>\n<li>The data in the backend system is constantly being updated so the caches need to be updated every N minutes.<\/li>\n<li>Requests to the backend system need to be throttled.<\/li>\n<\/ul>\n<p>Here&#8217;s a possible solution taking advantage of Akka actors and Scala&#8217;s support for functions as first class objects. \u00a0 The first piece of the puzzle is a <code>CacheSystem<\/code> which creates and queries EhCache caches:<\/p>\n<pre class=\"brush: scala\">class CacheSystem(name: String, updateIntervalMin: Int, cacheManager: CacheManager) {\r\n  var caches = List.empty[Cache]\r\n  val actorSystem = ActorSystem(\"cache_\" + name)\r\n\r\n  val DEFAULT_TTL_SEC = 86400   \/\/ 1 day\r\n\r\n  def addCache(name: String, size: Int, ttlSeconds: Int = DEFAULT_TTL_SEC): Cache = {\r\n    val config = new CacheConfiguration(name, size)\r\n    config.setTimeToIdleSeconds(ttlSeconds)\r\n    val cache = new Cache(config)\r\n    cacheManager.addCache(cache)\r\n    caches = cache :: caches\r\n    cache\r\n  }\r\n\r\n  def createCacheActor(cacheName: String, cacheSize: Int, scheduleDelay: Duration, \r\n                       actorCreator: (Cache, CacheSystem) =&gt; Actor, \r\n                       ttlSeconds: Int = DEFAULT_TTL_SEC): ActorRef = {\r\n\r\n    val cache = addCache(cacheName, cacheSize, ttlSeconds)\r\n    val actor = actorSystem.actorOf(Props(actorCreator(cache, this)), \r\n                                    name = cacheName + \"CacheActor\")\r\n\r\n    actorSystem.scheduler.schedule(scheduleDelay, updateIntervalMin minutes, \r\n                                   actor, UpdateCacheForNow)   \r\n    if (!DateUtil.isNowInActiveBusinessDay) {\r\n      actorSystem.scheduler.scheduleOnce(scheduleDelay, actor, \r\n                                         UpdateCacheForPreviousBusinessDay)\r\n    }\r\n\r\n    actor\r\n  }\r\n\r\n  def findCachedObject[T](key: String, cache: Cache, finder: () =&gt; T): Option[T] = {\r\n    val element = cache.get(key)\r\n\r\n    if (element == null) {\r\n      findObjectForCache(key, cache, finder)\r\n    } else {\r\n      Some(element.getObjectValue.asInstanceOf[T])\r\n    }\r\n  }\r\n\r\n  def findObjectForCache[T](key: String, cache: Cache, finder: () =&gt; T): Option[T] = {\r\n    val domainObj = finder()\r\n    if (domainObj != null) {\r\n      val element = new Element(key, domainObj)\r\n      cache.put(element)\r\n      Some(domainObj)\r\n    } else {\r\n      None\r\n    }\r\n  }\r\n\r\n  def clearAllCaches() {\r\n    caches.foreach(_.removeAll())\r\n  }\r\n}<\/pre>\n<p>The <code>createCacheActor<\/code> method creates a cache and an actor, and schedules tasks to periodically update the cache. I decided to use actors for this because the actor system&#8217;s thread pool is a good way to meet the throttling requirement. In addition using the Akka API it is easy to have scheduled tasks send messages to actors. \u00a0<code>createCacheActor<\/code> takes a function of \u00a0<code>(Cache, CacheSystem) =&gt; Actor<\/code> to create the actor. \u00a0 It then fills in those parameters to create the actor using the Akka <code>actorOf<\/code> method.<\/p>\n<p>The <code>findCachedObject<\/code> and <code>findObjectForCache<\/code> methods take a <code>finder<\/code> function of <code>() =&gt; T<\/code> that handles the lookup of objects from the backend system.<\/p>\n<p>Here is an example of the <code>CacheSystem<\/code> being used by the business logic layer:<\/p>\n<pre class=\"brush: scala\">class CachingBusinessService(bizService: BusinessService) extends BusinessService {\r\n  implicit val timeout = Timeout(60 seconds)\r\n\r\n  val service1CacheActor = \r\n    cacheSystem.createCacheActor(\"service1\", DATE_CACHE_SIZE, 0 seconds, \r\n                                 new Service1CacheActor(_, _, bizService))\r\n  \/\/ ... more actors created here\r\n\r\n  def service1(date: Date, useFoo: Boolean): JList[Service1Result] = {\r\n    val future = \r\n      service1CacheActor ? FindValue(new Service1Params(date, useFoo))\r\n    Await.result(future, timeout.duration).asInstanceOf[JList[Service1Result]]\r\n  }\r\n\r\n  \/\/ ... more service methods\r\n}<\/pre>\n<p>The <code>CachingBusinessService<\/code> is a caching implementation of the <code>BusinessService<\/code> interface. It creates <code>CacheActor<\/code>s to service the requests. \u00a0 To create the <code>Service1CacheActor<\/code> it passes a curried constructor to <code>createCacheActor<\/code>.<\/p>\n<p>The caching implementation of <code>service1<\/code> sends a <code>FindValue<\/code> message to the <code>service1CacheActor<\/code>, using the <code>?<\/code> (<code>ask<\/code>) method which returns an Akka <code>Future<\/code>. \u00a0Then it waits for the result of the future and returns it to the caller.<\/p>\n<p>Using <code>Await.result<\/code> should raise a red flag. You don&#8217;t want to block if you don&#8217;t have to (epsecially inside of an actor). However in this case the <code>BusinessService<\/code> is being called as part of a REST API served by a non-async HTTP server. Before the caching layer was introduced it would block waiting for the back end to to respond.<\/p>\n<p>Here&#8217;s the code for the <code>FindValue<\/code> message and the <code>Params<\/code> that it contains. \u00a0<code>Params<\/code> are the parameters for the backend query. Each unique <code>Params<\/code> object corresponds to a cache entry so each <code>Params<\/code> subclass is responsible for generating the appropriate cache key.<\/p>\n<pre class=\"brush: scala\">object CacheActor {\r\n  case class FindValue(params: Params)\r\n\r\n  trait Params {\r\n    def cacheKey: String\r\n  }\r\n}<\/pre>\n<p>In the <a href=\"http:\/\/localhost\/wordpress\/2012\/07\/an-auto-updating-caching-system-part-2\/\">next post<\/a> I&#8217;ll describe the <code>CacheActor<\/code> class hierarchy.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Imagine you needed to build a caching system in front of a slow backend system with the following requirements: The data in the backend system is constantly being updated so the caches need to be updated every N minutes. Requests to the backend system need to be throttled. Here&#8217;s a possible solution taking advantage of [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5,3],"tags":[],"class_list":["post-224","post","type-post","status-publish","format-standard","hentry","category-akka","category-scala","entry"],"_links":{"self":[{"href":"https:\/\/sourcedelica.com\/blog\/wp-json\/wp\/v2\/posts\/224","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/sourcedelica.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sourcedelica.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sourcedelica.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/sourcedelica.com\/blog\/wp-json\/wp\/v2\/comments?post=224"}],"version-history":[{"count":58,"href":"https:\/\/sourcedelica.com\/blog\/wp-json\/wp\/v2\/posts\/224\/revisions"}],"predecessor-version":[{"id":525,"href":"https:\/\/sourcedelica.com\/blog\/wp-json\/wp\/v2\/posts\/224\/revisions\/525"}],"wp:attachment":[{"href":"https:\/\/sourcedelica.com\/blog\/wp-json\/wp\/v2\/media?parent=224"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sourcedelica.com\/blog\/wp-json\/wp\/v2\/categories?post=224"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sourcedelica.com\/blog\/wp-json\/wp\/v2\/tags?post=224"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}