PlayFramework: Delay a route / response

29 Jul
2019

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 } } }

and of course, enable the filter in your application.conf

play.filters.enabled+=mypackage.filters.DelayFilter

Did this help you in your project? Let me know in the comments!

Comment Form

top