Skip to content

Instantly share code, notes, and snippets.

@mjamesruggiero
Last active August 29, 2015 14:18
Show Gist options
  • Save mjamesruggiero/e99dab73b7a84bd5aebb to your computer and use it in GitHub Desktop.
Save mjamesruggiero/e99dab73b7a84bd5aebb to your computer and use it in GitHub Desktop.
package com.mjamesruggiero
import scalaz.State
object StateMonad {
type StateCache[+A] = State[Cache, A]
trait ConfigService {
def value(k: String): StateCache[ConfigValue]
}
case class ConfigValue(
key: String,
value: String)
case class Timestamped[A](value: A, timestamp: Long)
case class Cache(
vals: Map[String, Timestamped[ConfigValue]],
hits: Int,
misses: Int)
{
def get(key: String): Option[Timestamped[ConfigValue]] = {
val desired = vals.get(key)
println(s"pulled ${desired} from a cached map")
desired
}
def update(k: String, s: Timestamped[ConfigValue]): Cache = {
println("caching the value")
Cache(vals + (k -> s), hits, misses)
}
}
object FakeConfigService extends ConfigService {
def value(k: String) = for {
oConfigV <- checkCache(k)
configV <- oConfigV match {
case Some(configV) => State.state[Cache, ConfigValue](configV)
case None => retrieve(k)
}
//_ = println(s"when I look in checkCache, I find ${checkCache(k)}")
} yield configV
private def checkCache(k: String): StateCache[Option[ConfigValue]] = State { c =>
c.get(k) match {
case Some(Timestamped(configV, ts))
if (!stale(ts)) => {
println(s"key '${k}' NOT stale!")
(c.copy(hits = c.hits + 1), Some(configV))
}
case other => {
println(s"key '${k}' stale!")
(c.copy(misses = c.misses + 1), None)
}
}
private def stale(ts: Long): Boolean = {
val fiveMinutes = 5 * 60 * 1000L
System.currentTimeMillis - ts > fiveMinutes
}
private def retrieve(k: String): StateCache[ConfigValue] = for {
configV <- State.state(callWebService(k))
tConfigV = Timestamped(configV, System.currentTimeMillis)
_ <- State.modify[Cache] { println(s"updating '${k}"); _.update(k, tConfigV) }
} yield configV
private def callWebService(k: String): ConfigValue = {
println("you actually called the webservice")
ConfigValue(k, "fakeValue")
}
}
}
@mjamesruggiero
Copy link
Author

implicit val CacheMonoid = new Monoid[Cache] { 
    override def zero = Cache(Map.empty, 0, 0)
    override def append(a: Cache, b: => Cache) =
        Cache(a.vals  ++ b.vals, a.hits + b.hits, a.misses + b.misses)
}
scala> import scalaz._, Scalaz._, Unapply._
scala> import com.mjamesruggiero.StateMonad._
scala> FakeConfigService.value("bingo").replicateM(10).run(CacheMonoid.zero)
pulled None from a cached map
key 'bingo' stale!
you actually called the webservice
updating 'bingo
caching the value
pulled Some(Timestamped(ConfigValue(bingo,fakeValue),1428614584353)) from a cached map
key 'bingo' NOT stale!
pulled Some(Timestamped(ConfigValue(bingo,fakeValue),1428614584353)) from a cached map
key 'bingo' NOT stale!
pulled Some(Timestamped(ConfigValue(bingo,fakeValue),1428614584353)) from a cached map
key 'bingo' NOT stale!
pulled Some(Timestamped(ConfigValue(bingo,fakeValue),1428614584353)) from a cached map
key 'bingo' NOT stale!
pulled Some(Timestamped(ConfigValue(bingo,fakeValue),1428614584353)) from a cached map
key 'bingo' NOT stale!
pulled Some(Timestamped(ConfigValue(bingo,fakeValue),1428614584353)) from a cached map
key 'bingo' NOT stale!
pulled Some(Timestamped(ConfigValue(bingo,fakeValue),1428614584353)) from a cached map
key 'bingo' NOT stale!
pulled Some(Timestamped(ConfigValue(bingo,fakeValue),1428614584353)) from a cached map
key 'bingo' NOT stale!
pulled Some(Timestamped(ConfigValue(bingo,fakeValue),1428614584353)) from a cached map
key 'bingo' NOT stale!
res33: (com.mjamesruggiero.StateMonad.Cache,
 List[com.mjamesruggiero.StateMonad.ConfigValue]) = (Cache(Map(bingo -> Timestamped(ConfigValue(bingo,
fakeValue), 1428614584353)), 9, 1), List(ConfigValue(bingo, fakeValue), ConfigValue(bingo, fakeValue),
 ConfigValue(bingo, fakeValue), ConfigValue(bingo, fakeValue), ConfigValue(bingo, fakeValue),
ConfigValue(bingo, fakeValue), ConfigValue(bingo, fakeValue), ConfigValue(bingo, fakeValue),
ConfigValue(bingo, fakeValue), ConfigValue(bingo, fakeValue)))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment