Scheduling a task in Java within a CompletableFuture

When we want to do something later in our Java code, we often turn to the ScheduledExecutorService. This class has a method called schedule(), and we can pass it some code to be run later like this:

ScheduledExecutorService executor =
    Executors.newScheduledThreadPool(4);
executor.schedule(
    () -> {System.out.println("..later");},
    1,
    TimeUnit.SECONDS
);
System.out.println("do...");
// (Don't forget to shut down the executor later...)

The above code prints “do…” and then one second later it prints “…later”.

We can even write code that does some work and returns a result in a similar way:

// (Make the executor as above.)
ScheduledFuture future = executor.schedule(
    () -> 10 + 25, 1, TimeUnit.SECONDS);
System.out.println("answer=" + future.get())

The above code prints “answer=35”. When we call get() it blocks waiting for the scheduler to run the task and mark the ScheduledFuture as complete, and then returns the answer to the sum (10 + 25) when it is ready.

This is all very well, but you may note that the Future returned from schedule() is a ScheduledFuture, and a ScheduledFuture is not a CompletableFuture.

Why do you care? Well, you might care if you want to do something after the scheduled task is completed. Of course, you can call get(), and block, and then do something, but if you want to react asynchronously without blocking, this won’t work.

The normal way to run some code after a Future has completed is to call one of the “then*” or “when*” methods on the Future, but these methods are only available on CompletableFuture, not ScheduledFuture.

Never fear, we have figured this out for you. We present a small wrapper for schedule that transforms your ScheduledFuture into a CompletableFuture. Here’s how to use it:

CompletableFuture future =
    ScheduledCompletable.schedule(
        executor,
        () -> 10 + 25,
        1,
        TimeUnit.SECONDS
     );
future.thenAccept(
    answer -> {System.out.println(answer);}
);
System.out.println("Answer coming...")

The above code prints “Answer coming…” and then “35”, so we can see that we don’t block the main thread waiting for the answer to come back.

So far, we have scheduled a synchronous task to run in the background after a delay, and wrapped its result in a CompletableFuture to allow us to chain more tasks after it.

In fact, what we often want to do is schedule a delayed task that is itself asynchronous, and already returns a CompletableFuture. In this case it feels particularly natural to get the result back as a CompletableFuture, but with the current ScheduledExecutorService interface we can’t easily do it.

It’s OK, we’ve figured that out too:

Supplier> asyncTask = () ->
    CompletableFuture.completedFuture(10 + 25);
CompletableFuture future =
    ScheduledCompletable.scheduleAsync(
        executor, asyncTask, 1, TimeUnit.SECONDS);
future.thenAccept(
    answer -> {System.out.println(answer);}
);
System.out.println("Answer coming...")

The above code prints “Answer coming…” and then “35”, so we can see that our existing asynchronous task was scheduled in the background, and we didn’t have to block the main thread waiting for it. Also, under the hood, we are not blocking the ScheduledExecutorService‘s thread (from its pool) while the async task is running – that task just runs in whatever thread it was assigned when it was created. (Note: in our example we don’t really run an async task at all, but just immediately return a completed Future, but this does work for real async tasks.)

I know you’re wondering how we achieved all this. First, here’s how we run a simple blocking task in the background and wrap it in a CompletableFuture:

public static  CompletableFuture schedule(
    ScheduledExecutorService executor,
    Supplier command,
    long delay,
    TimeUnit unit
) {
    CompletableFuture completableFuture = new CompletableFuture<>();
    executor.schedule(
        (() -> {
            try {
                return completableFuture.complete(command.get());
            } catch (Throwable t) {
                return completableFuture.completeExceptionally(t);
            }
        }),
        delay,
        unit
    );
    return completableFuture;
}

And here’s how we delay execution of an async task but still return its result in a CompletableFuture:

public static  CompletableFuture scheduleAsync(
    ScheduledExecutorService executor,
    Supplier> command,
    long delay,
    TimeUnit unit
) {
    CompletableFuture completableFuture = new CompletableFuture<>();
    executor.schedule(
        (() -> {
            command.get().thenAccept(
                t -> {completableFuture.complete(t);}
            )
            .exceptionally(
                t -> {completableFuture.completeExceptionally(t);return null;}
            );
        }),
        delay,
        unit
    );
    return completableFuture;
}

Note that this should all work to run methods like exceptionally(), thenAccept(), whenComplete() etc.

Feedback and improvements welcome!

Rabbit Escape 0.12 out now, with water

The newest feature of Rabbit Escape, water, has been brewing a long time, but we now think it’s ready:

Water can flow, it can put out fires, and it can drown rabbits.

Rabbots seem to be immune though…

Check out the 20 new levels we have released! (This makes a total of 180 levels.)

It works on Windows, Linux, Mac OS and Android.

Convert a video to a GIF with reasonable colours

Here’s a little script I wrote to avoid copy-pasting the ffmpeg command from superuser every time I needed it.

It converts a video to a GIF file by pre-calculating a good palette, then using that palette.

Usage:

./to_gif input.mp4 output.gif

The file to_gif (which should be executable):

#!/bin/bash

set -e
set -u

# Credit: https://superuser.com/questions/556029/how-do-i-convert-a-video-to-gif-using-ffmpeg-with-reasonable-quality

INPUT="$1"
OUTPUT="$2"

PALETTE=$(tempfile --suffix=.png)

ffmpeg -y -i "${INPUT}" -vf palettegen "${PALETTE}"
ffmpeg -y -i "${INPUT}" -i "${PALETTE}" \
    -filter_complex "fps=15,paletteuse" "${OUTPUT}"

rm -f "${PALETTE}"

Note: you might want to modify the number after fps= to adjust how fast the video plays.

Gradle: what is a task, and how can I make a task depend on another task?

In an insane world, Gradle sometimes seems like the sanest choice for building a Java or Kotlin project.

But what on Earth does all the stuff inside build.gradle actually mean?

And when does my code run?

And how do you make a task?

And how do you persuade a task to depend on another task?

[Related: Clever things people do in Groovy so you have to know about them]

Setting up

To use Gradle, get hold of any version of it for long enough to create a local gradlew file, and the use that.

$ mkdir gradle-experiments
$ cd gradle-experiments
$ sudo apt install gradle  # Briefly install the system version of gradle
...
$ gradle wrapper --gradle-version=5.2.1
$ sudo apt remove gradle   # Optional - uninstalls the system version
$ ./gradlew tasks
... If all is good, this should ...
... print a list of available tasks. ...

It is normal for gradlew and the whole gradle/ directory it creates to be checked into source control. This means everyone who fetches the code from source control will have a predictable Gradle version.

What is build.gradle?

build.gradle is a Groovy program that Gradle runs within a context that it has set up for you. That context means that you are actually calling methods of a Project object, and modifying its properties. The fact that Groovy lets you miss out a lot of punctuation makes that harder to see, but it’s true.

The first thing to get your head around is that Gradle actually runs your code immediately, so if your build.gradle looks like this (and only this):

println("Hello")

when you run Gradle your code runs:

$ ./gradlew -q 
Hello
... more guff ...

So that code runs even if you don’t ask Gradle to run a task containing that code. It runs at “configuration time” – i.e. when Gradle is understanding your build.gradle file. Actually, “understanding” it means executing it.

Remember when I said this code runs in the context of a Project? What that means is that if you have something like this in your build.gradle:

repositories {
    jcenter()
}

what it really means is something like this:

project.repositories(
    {
        it.jcenter()
    }
)

You are calling the repositories method on the project object. The argument to the repositories method is a Groovy closure, which is a blob of code that will get run later. I’ve used the magic it name above to demonstrate that jcenter is just a method being called on the object that is the context for the closure when it is run.

When does it run? Let’s find out:

println("before")
project.repositories( {
    println("within")
    jcenter()
})
println("after")
$ ./gradlew -q
before
within
after
... more guff ...

This surprised me – it means the closure you pass in to repositories is actually run immediately, as part of running repositories, before execution gets to the line after that call.

As we’ll see later, some closures you create do not run immediately like this one.

Once you know that build.gradle is actually modifying a Project object, you have starting point for understanding the Gradle reference documentation.

How do you make a task?

You probably shouldn’t do it very often, but it was instructive for me to understand how to make my own custom task. Here’s an example:

tasks.register("mytask") {
    doLast {
        println("running mytask")
    }
}

This creates a new task by calling the register method on the tasks property of the Project object. Register takes two arguments: a name for the task (“mytask” here), and a closure with some code in it to run when we decide we need this task. That closure gets run in a context that can’t see the Project object, but instead can see a Task object which it is helping to make. That Task object has a doLast method that we call, passing it a closure that will be run when the task is actually executed (not immediately).

If we remove some of the syntactic sugar the above build.gradle looks like this:

tasks.register(
    "mytask",
    {
        it.doLast(
            {
                println("running mytask")
            }
        )
    }
)

Above we can see that register really does take two arguments as I said above – the first version uses a Groovy feature where if you miss out the last argument and write a closure immediately afterwards the closure is passed as the last argument. Confusing, eh?

Again, notice that doLast is a method on the Task object that is implicitly available when the closure is run.

So we have created a task that we can run:

 ./gradlew -q mytask
running mytask

How do you make a task depend on another task?

If I want to run my code formatting before my compile (for example) I sometimes need to modify a task to make it depend on another one. This can done for tasks you create or for pre-existing ones. Here’s an example:

plugins {
    id "java"
}
tasks.register("mytask") {
    doLast {
        println("running mytask")
    }
}
compileJava {
    dependsOn tasks.named("mytask")
}

So, calling the plugins method on the Project at the top with a closure that ran the id method on something modified the Project so that it had a new method called compileJava which we called at the bottom, passing it a closure to run. That closure ran in the context of a Task object (similar to when we created a task, but now allow us to modify a pre-existing one). We called the dependsOn method of the Task object, passing in another Task object which we had got by calling the named method on the tasks object.

[Side note: the register method actually returns a Task object that we could have passed to dependsOn without looking it up again using named, but Groovy doesn’t provide a very convenient way of holding on to that reference, so we didn’t do it. The Kotlin example below shows that this is quite simple in Kotlin.]

How do I do all this in Kotlin?

Because one DSL that hides what’s really going on wasn’t enough for you, Gradle now provides a second DSL that hides what’s going on in subtly different ways, which is a program written in Kotlin instead of Groovy. This is marginally better, because Kotlin doesn’t let you do quite so many stupid tricks as Groovy does.

Below are all our examples in Kotlin. You get started exactly the same way, by following “Setting up” above. Remember to name your build file build.gradle.kts.

Say hello in Gradle Kotlin

println("Hello")

This is identical to the Groovy version.

Use jcenter repo in Gradle Kotlin

repositories {
    jcenter()
}

This is identical to the Groovy version, and with the same meaning: repositories is a method on the implicitly-available Project object.

The “unsugared” version looks like this in Kotlin:

this.repositories(
    {
        this.jcenter()
    }
)

[Note that the word this is used to access the implicit context. The word it has a different meaning in Kotlin from in Groovy. In Groovy it means the implicit context, but in Kotlin it means the first argument. We didn’t pass any arguments to jcenter when we called it, so we can’t use it, but we were being run in a context, which we can refer to using this. Simple. huh?]

Execution order in Gradle Kotlin

We this build.gradle.kts:

println("before")
project.repositories( {
    println("within")
    jcenter()
})
println("after")

We see this behaviour:

$ ./gradlew -q
before
within
after

which is all identical to the Groovy version.

Making a new task in Gradle Kotlin

tasks.register("mytask") {
    doLast {
        println("running mytask")
    }
}

Notice that Kotlin lets you do the same trick as Groovy: providing an extra argument to a function that is a closure by writing it immediately after it looks like you’ve finished calling it. It’s good for people who dislike closing brackets hanging around longer than they’re welcome. As someone who likes Lisp, I’m OK with closing brackets, but what do I know?

The above is identical to the Groovy version, but slightly different when unsugared:

tasks.register(
    "mytask",
    {
        this.doLast(
            {
                println("running mytask")
            }
        )
    }
)

One task depending on another in Gradle Kotlin

plugins {
    java
}
val mytask = tasks.register("mytask") {
    doLast {
        println("running mytask")
    }
}
tasks.compileJava {
    dependsOn(mytask)
}

This differs slightly from the Groovy version, even though the meaning is the same: we start off in the context of a Project object that we call methods on.

The code to make one task depend on another gets hold of the Task object called compileJava from inside the tasks property of the Project, and calls it (because it’s a callable object). We pass in a closure that runs in the context of this Task object, calling its dependsOn method, and passing in a reference to the mytask object, which is a Task and was created in the code above.

Corrections and clarifications welcome

The above is what I have worked out by experimentation and trying to read the Gradle documentation. Please add comments that clear up confusions and correct mistakes.