In an event-sourced environment, you sometimes have to introduce an artificial delay to some actions to make sure read-sides had the time to update themselves. If you’re using the classic routing mechanism with a routes-file, you can add such a delay declaratively, like here:
+ delay800
PUT /products/:productId controllers.ProductCRUDController.update(productId: UUID)
This would delay the response of the update-action by 800 Milliseconds, hopefully giving the other consuming services enough time to catch up.
To make this work, you have to add a filter to your application, like this one:
import akka.actor.ActorSystem
import akka.stream.Materializer
import play.api.mvc.{Filter, RequestHeader, Result}
import play.api.routing.Router
import scala.concurrent.duration._
import scala.concurrent.{ExecutionContext, Future}
class DelayFilter(val mat: Materializer, implicit val ec: ExecutionContext, actorSystem: ActorSystem) extends Filter {
override def apply(nextFilter: RequestHeader => Future[Result])(rh: RequestHeader): Future[Result] = {
val handler = rh.attrs.get(Router.Attrs.HandlerDef)
val delay: Option[Int] = handler
.flatMap(
_.modifiers
.find(s => s.startsWith("delay")))
.map(s => Integer.parseInt(s.substring("delay".length)))
.filter(_ > 0)
val result = nextFilter.apply(rh)
delay match {
case Some(d) => akka.pattern.after(d.millis, actorSystem.scheduler)(result)
case None => result
}
}
}
Code language: Scala (scala)
and of course, enable the filter in your application.conf
play.filters.enabled+=mypackage.filters.DelayFilter
Code language: Properties (properties)
Did this help you in your project? Let me know in the comments!