Skip to main content

How to run Scala tasks on a time schedule

Problem

You want to run a background task in your Scala application on a specified schedule. Or want to trigger a specific functionality of your app at a specific point in time, or at fixed intervals.

Solution

For these kinds of situations, you can rely on the TimerTask class that Java provides. The way it works is that you basically need to extend that class and implement the run method.

Then you simply need to create a Timer and invoke the .schedule or .scheduleAtFixedRate methods to "register" the task that you defined previously. You also need to pass a delay value with the milliseconds before the task is to be executed, or a specific date with when you want the task to be executed.

The interesting part here is that you can create the timer as val timer: Timer = new Timer(true), being that true value if you want to run the Timer as a daemon. That means that your application won't stop there waiting for the execution, but it will continue to run, and eventually, when the time condition is met, the task will run.

Let's take a look at some examples:

Example: Execution after 10 seconds after the registration

In this example, we define a Task1 that extends TimerTask and we schedule it to run 5 seconds after the registration.

import java.util.{Timer, TimerTask}

// Define the task that you want to schedule
class Task1 extends TimerTask {
override def run(): Unit = {
// Do some interesting stuff
val currentTime = new Timestamp(System.currentTimeMillis())
println(s"${currentTime} - Task 1")
}
}

// Register the Timer and the task
val task1: TimerTask = new Task1()
val delay1: Long = 5000 // 5 seconds

val timer: Timer = new Timer(true) // True for running as daemon
timer.schedule(task1, delay1)

Example: Execution at fixed rate every 10 seconds

In this example we will use the scheduleAtFixedRate, we define Task1 that extends TimerTask and we schedule it to run 5 seconds after the registration and every 5 seconds, those are the delay and period arguments of the method.

import java.util.{Timer, TimerTask}

// Define the task that you want to schedule
class Task1 extends TimerTask {
override def run(): Unit = {
// Do some interesting stuff
val currentTime = new Timestamp(System.currentTimeMillis())
println(s"${currentTime} - Task 1")
}
}

// Register the Timer and the task
val task1: TimerTask = new Task1()
val delay1: Long = 5000 // 5 seconds

val timer: Timer = new Timer(true) // True for running as daemon
timer.scheduleAtFixedRate(task1, delay1, delay1)

Checking the logs:

2023-05-28 19:16:31.028 - Task 1
2023-05-28 19:16:36.028 - Task 1
2023-05-28 19:16:41.027 - Task 1
2023-05-28 19:16:46.027 - Task 1

Example: Execution at specific time

In this example, we will use the schedule method. We define Task1 that extends TimerTask and we schedule it to run at 20:00:00.

import java.util.{Timer, TimerTask}

// Define the task that you want to schedule
class Task1 extends TimerTask {
override def run(): Unit = {
// Do some interesting stuff
val currentTime = new Timestamp(System.currentTimeMillis())
println(s"${currentTime} - Task 1")
}
}

// Register the Timer and the task
val task1: TimerTask = new Task1()
val dateToRun = Timestamp.valueOf("2023-05-28 20:00:00")

val timer: Timer = new Timer(true)
timer.schedule(task1, dateToRun)

Source

You can find more information of how this works here:

https://docs.oracle.com/javase/8/docs/api/java/util/Timer.html

https://docs.oracle.com/javase/8/docs/api/java/util/TimerTask.html