Run specific Gradle tasks in sequence

Is there any way to run only a certain Gradle task sequentially, while running others in parallel?

Run specific Gradle tasks in sequence
Photo by Bradyn Trollip / Unsplash

Is there any way to turn off parallel execution for a particular Gradle task?

It seems a bit weird to even consider such thing in the first place... But there are some cases in which you actually might want a particular type of task to execute sequentially, even though you are using --parallel=true for the remaing tasks.

For example, this StackOverflow thread asks for SpotBugs tasks to run in sequence to ease on the resources consumption. Or maybe you have a particular task, say an integration test, that needs to use a shared resource, like a TCP port, and you don't want that particular test to run in parallel with others.

In any case, the solution is simple: we can use a Gradle feature called Build Service.

I could not find a quick answer on Google with examples, so here's one.

First let's create a build service:

import org.gradle.api.services.BuildService;
import org.gradle.api.services.BuildServiceParameters;

public abstract class RunInSequence implements BuildService<BuildServiceParameters.None> {}

Now, add it to the task that needs to run in sequence:

import org.gradle.api.provider.Property;
import org.gradle.api.tasks.Internal;

public abstract class MyTask extends DefaultTask {
    @Internal
    public abstract Property<RunInSequence> getRunInSequence();
}

Great! Now we need to use a service provider in a plugin where our task is declared:

import org.gradle.api.Plugin;
import org.gradle.api.Project;

class MyPlugin implements Plugin<Project> {
    @Override
    public void apply(Project project) {
        var serviceProvider = project
            .getGradle()
            .getSharedServices()
            .registerIfAbsent(
                "runInSequence",
                RunInSequence.class,
                s -> { s.getMaxParallelUsages().set(1); }
            );

        project.getTasks()
            .register( 
                "myTask",
                MyTask.class,
                t -> {
                    t.getRunInSequence().set(serviceProvider);
                    t.usesService(serviceProvider);
                });
    }
}

And that's it!

Next time you use myTask in multiple Gradle modules, all occurences of this task will wait for each other and run in sequence!

Subscribe to darlanalv.es

Sign up now to get access to the library of members-only issues.
Jamie Larson
Subscribe