Luis Muñiz
Luis Muñiz

Reputation: 4811

How to define a default dependsOn in a Custom Task

I'm relatively new to gradle. In order to create an automated deployment script on a cluster, I have created a bunch of Custom tasks that will depend on each other. For example:

class StartSchedulerTask extends SchedulerTask {
    @TaskAction
    void start() {
        dependsOn env.nodes.name.collect {"startTomcat_$it"}
        println "Starting quartz on node: ${node}"
    }
}

in build.gradle, i have dynamically created the tasks:

project.extensions.environment.nodes.each { TomcatNode n ->
    String name = n.name
    task "nodeInit_$name"(type: DeployToNodeInitTask) {
                node(n)
    }
    task "stopWorker_$name"(type: StopWorkerTask) {
        node(n)
    }
    task "stopTomcat_$name"(type: StopTomcatTask){
        node(n)
    }
    task "updateAppConfigs_$name"(type: UpdateAppConfigsTask){
        node(n)
        apps(V3Application.ALL_APPS)
        buildName('develop')
    }
    task "deployWars_$name"(type: DeployWarsTask){
        node(n)
        apps(V3Application.ALL_APPS)
        buildName('develop')
    }
    task "startTomcat_$name"(type: StartTomcatTask){
        node(n)
    }
    task "startWorker_$name"(type: StartWorkerTask){
        node(n)
    }
    task "terminateNode_$name"(type: DeployToNodeTerminationTask){
        node(n)
    }
}
task stopScheduler(type: StopSchedulerTask) {
    environment(environment)
}
task startScheduler(type: StartSchedulerTask) {
    environment(environment)
}

The default task is configured to be startScheduler, which is the last step of the deployment process, the idea being that the task graph, once it is built, will take care of the correct execution order of my tasks.

However, when I print out the task graph, the only task listed is startScheduler. Am I missing something?

Upvotes: 0

Views: 3785

Answers (3)

Luis Muñiz
Luis Muñiz

Reputation: 4811

Thanks to the remark of Peter Niederwieser and Jeffrey, I was able to come up with the full solution I want. I did not mark Peter's as the answer, because the full answer is below, but it was a necessary hint to the right solution:

I Created an interface DependencyAware:

public interface DependencyAware {
    void declareDependencies()
}

Every task that knows how to declare its dependencies, implements this interface. For example:

class StartSchedulerTask extends SchedulerTask {

    @TaskAction
    void start() {
        println "Starting quartz on node: ${node}"
    }

    void declareDependencies() {
        dependsOn env.nodes.name.collect {"startTomcat_$it"}
    }
}

In my build script:

tasks.each { Task t ->
    if (t instanceof DependencyAware) {
        t.declareDependencies()
    }
}

That's it!

Thanks for the pointers Peter and Jeffrey

UPDATE 1

task deploy(dependsOn: ['backupWars', 'startScheduler'])

task stopScheduler(type: StopSchedulerTask)

task backupWars(type: BackupWarsTask)

project.extensions.targetEnvironment.nodes.each { TomcatNode n ->
    String name = n.name
    [
        ("nodeInit_$name"): DeployToNodeInitTask,
        ("stopWorker_$name"): StopWorkerTask,
        ("stopTomcat_$name"): StopTomcatTask,
        ("updateAppConfigs_$name"): UpdateAppConfigsTask,
        ("deployWars_$name"): DeployWarsTask,
        ("startTomcat_$name"): StartTomcatTask,
        ("startWorker_$name"): StartWorkerTask,
        ("terminateNode_$name"): DeployToNodeTerminationTask,
    ].each { String taskName, Class taskType ->
        task "$taskName"(type: taskType) {
            node(n)
        }
    }
}

task startScheduler(type: StartSchedulerTask) {
    dryRun(testMode)
}

The internal dependencies between the different deployment steps, are in the tasks themselves, for example:

class StartWorkerTask extends WorkerTask {

    @TaskAction
    void start() {
        println "Starting worker ${node}"
    }

    void declareDependencies() {
        dependsOn tomcatOnThisNodeHasBeenStarted()
    }

    String tomcatOnThisNodeHasBeenStarted() {
        "startTomcat_${node.name}"
    }
}

The declaration of the topology is as follows:

environments {
    prod {
        nodes {
            (1..2).each { int i ->
                "w${i}_prod" {
                    host = "prod-n$i"
                    userName = "xxxxx"
                    password = "xxxxx"
                    loadBalancer = 'lb_prod'
                    frontendJkManagerUrl = 'http://web01/jkmanager'
                }
            }

            scheduler {
                name = "w1_prod"
            }
        }
    }
    rc {
    //rc topology here
    }
}

Upvotes: 3

Peter Niederwieser
Peter Niederwieser

Reputation: 123996

Task dependencies have to be declared at configuration time, not at execution time. In theory you could do so in the task's constructor, but a better approach is to do it in the build script, or in a plugin.

Upvotes: 3

Jeffrey Theobald
Jeffrey Theobald

Reputation: 2617

It's because you're declaring the dependency from inside the @TaskAction method. The @TaskAction only runs once the dependency graph has been formed.

You could abuse DoFirst() inside your @TaskActions methods to call all your dependencies, but this won't turn up on the dependency graph.

Upvotes: 2

Related Questions