Play background tasks and async services

Hey, I’m wondering what is the correct way to work with async services (returns Future[OfResult]) inside Play background akka tasks. There is no information about it in play docs, It seems I can’t just return Future[TaskResult] at the end and get things done in a reactive way, so I’m using Await.result for each async service call. And even if I use my own custom execution context, sometimes I get weird exceptions from slick db layer and task stops working, this is not resilient at all (I would expect at least next schedule to work) so I think I’m doing it wrong.

The task is simple, I have an events table in database with some fields and date range, each day I’m checking if current date is inside date range, I remove passed events and activate new events. It requires me to:

  1. Get all events - which is list of Future[Event]
  2. Get through the list and modify or delete events

I’m doing it in procedural style with blocking Await.result

With small events count it fails very rare but with like thousands - it fails pretty soon (I assume because of limited database pool?)

It doesn’t look like just wrong database configuration because in regular async controller action everything works fine with huge amount of data so I suppose I’m doing it wrong

Hi @cutoffurmind,

This sounds like a perfect use case for reactive streams. IIUC, every day you run a job that is doing some database maintenance. The job may load a few or a huge number of rows from the database. So, I’d consider using Alpakka’s support for Slick and build a Source you can then plug to any Flow with your logic.
Once you had that stream built, I’d put it all inside an actor and supervise the actor so that when it fails it is restarted with some backoff.
Finally, I’d use a scheduler to send a Tick message to the actor (you have the scheduler in the actor and send the messages to self) to trigger a new creation and execution of the stream.

The problem though, is that if you have multiple copies of your play application with one instance of this actor, then those multiple instances will compete. One option is to add a lock on the database so only one instance can acquire the lock and perform the task (include a timeout on the lock so that lock expire and add node info in the lock so that a node can reenter and reacquire the lock). the alternative is to make all your Play processes build an Akka Cluster and make the actor with the stream an AkkaCluster Singleton.

Cheers,

I have only one play instance so it’s fine, thanks, I’ll try to dig it