Gradle wartet auf Service in Docker Container

Im Zusammenhang mit automatisierten Applikationstest war in einem späteren Schritt einer Deployment Pipeline eine Applikation in einer Testumgebung zu starten, um danach JUnit-Tests auszuführen. Die Applikation war eine Spring Boot Applikation innerhalb eines Docker Containers. Als Build Tool kam Gradle zum Einsatz. Wenn man nun mit Docker den Container startet, dann beendet das Docker CLI sofort nachdem es den Java-Prozess innerhalb des Containers gestartet hat. Will man nun sofort mit den Tests beginnen, dann ist die Spring Boot Applikation aber eventuell noch nicht vollständig gestartet und die Tests schlagen fehl.Eine einfache Variante ist, innerhalb des Builds für eine gewisse Zeit zu warten. Eine elegantere Variante ist, explizit so lange zu Warten bis die Services Verfügbar sind und dann die automatisierten Tests zu starten. Auf diese Weise hält man Wartezeit so kurz wie möglich.

Unsere Applikation hat seine Dienste via HTTP angeboten. Also habe ich einen Task in Gradle eingebaut, der solange wartet bis der Service verfügbar ist. Ein Timeout , falls der Service auf Grund eines Fehlers gar nicht startet, ist auch vorhanden.

Hier das Fragement aus dem Build-Skript:

...
task up(type: Exec, group: 'docker') {
    dependsOn pull

    workingDir composeRunDir
    commandLine 'docker-compose', 'up', '-d', '--force-recreate'
}

test.dependsOn 'up'
test.doFirst {
    int maxSec = 60
    println ("Wait for Service Started for ${maxSec} seconds.")
    for(int i = 0; i < maxSec; i++) {
        print ("Try after ${i} seconds. ")
        try {
            new URL("http://localhost:8080/")
                    .getText(connectTimeout: 5_000,
                    readTimeout: 10_000,
                    useCaches: false,
                    allowUserInteraction: false,
                    requestProperties: ['Connection': 'close'])
            println ("Service available.")
            return
        } catch (e) {
            println (e)
            sleep(1000)
        }
    }
    org.gradle.api.GradleException("Giving up. Service for testing not available.")
}
test.finalizedBy 'remove'
...

Wie im Beispiel zu sehen ist, wird docker-componse benutzt. Wenn man nun mehrere Services in Docker-Compose startet und ein Service soll warten bis der andere Service vollständig gestartet ist, dann kann man Tools wie wait-for-it oder dockerize benutzen, da auch docker-compose nicht wartet, bis ein Service vollständig gestartet ist.

  1. Deployment Pipeline: Martin Fowler – http://martinfowler.com/bliki/DeploymentPipeline.html
  2. Spring Boot – http://projects.spring.io/spring-boot/
  3. Docker – https://www.docker.com/
  4. Gradle – https://gradle.org/
  5. JUnit – http://junit.org
  6. Controlling startup order in compose – https://docs.docker.com/compose/startup-order/

Leave a comment