-1

We have an ApplicationRunner to create an admin user on the first start of a spring boot application.

To create the user, it must connect to an auth server (we use Keycloak). However, if the service is deployed together with the main application (via docker-compose up -d) it will take some time until the auth server is available, actually, too long. The ApplicationRunner will fail with a 502 Bad Gateway exception, because it is executed before the auth server is up and running.

How can the ApplicationRunner delay creating the admin until the auth server is up?

Ideally, the ApplicationRunner should delay everything and provide some information about the "waiting state" during startup. If after e.g. 1 min or so the auth server is not available during startup, the application run should fail.

Notes We are using docker-compose version 3. We are looking for an application level solution, because docker-compose docs state that this should be handled on the application level.

Stuck
  • 11,225
  • 11
  • 59
  • 104
  • Do the techniques in [Docker Compose wait for container X before starting Y](https://stackoverflow.com/questions/31746182/docker-compose-wait-for-container-x-before-starting-y) work for you, or do you need something more directly written into the application? – David Maze Nov 19 '20 at 14:02

2 Answers2

0

As long as you use Docker-Compose, you can Control startup and shutdown order in Compose.

my-service:
    image: my-company/my-service:1.0.0
    container_name: my-service
    restart: on-failure
    depends_on:
      my-auth-server-service:
        condition: service_healthy
    ports:
      - 8080:8080

my-auth-server-service:
   image: ...
   container_name: ...
   ...

However, it doesn't guarantee the "readiness" of the service itself so an application-specific health or readiness check would be required (also described in the link above).

You might want define HEALTHCHECK in the Dockerfile of the authorization my-auth-server-service service (feel free to do in every service) to detect the health/readiness through a REST API call. As long as you use Spring, the actuator endpoint is suitable.

Here is a short example, however, you might want to define additional/custom logic being able to detect the complete readiness.

RUN apk --no-cache add curl

HEALTHCHECK --interval=20s --timeout=3s --retries=20 \
    CMD curl --fail http://localhost:8080/actuator/health || exit 1
Nikolas Charalambidis
  • 40,893
  • 16
  • 117
  • 183
  • Thanks, but docker-compose docs state: "Version 3 no longer supports the condition form of depends_on.". Also they hint, that this problem should not be solved in docker-compose but rather in the application code, which I originally posted the question tagged only as `spring boot`. – Stuck Nov 19 '20 at 14:17
  • Why did you mention docker-compose if you want to find a solution on the application level (tagged [tag:spring-boot]? The details of your question including the start-up desciption implies you are looking for a solution on the [tag:docker-compose] level. Moreover, you haven't stated you use the version 3. Please, edit the question to get more helpful asnwers. – Nikolas Charalambidis Nov 19 '20 at 14:36
  • ...because it is related to the deployment and providing context information may help better understanding the question. Version 3 is the current version as of the date of the question - I added notes to clarify things in the question anyway. – Stuck Nov 19 '20 at 14:53
  • There is no reason why this answer, full of so much valuable content, be DVed. If the question is not clear, the answer should not be penalized IMO. – Arvind Kumar Avinash Oct 15 '21 at 10:31
0

Conceptually, the startup procedure may just fail the complete application run, because it is an initialization script. Without success of this initialization the complete application cannot be used. The context / deployment should handle when to (re)start what.

If the initialization script fails (and consequently the complete application run), then using docker-compose's restart: unless-stopped configuration on the main application will just retry starting it. Eventually, the auth server gets up in the meantime and finally the main service is up running.

Turns out that implementing ApplicationRunner it is not as easy to stop the complete application context during startup. Instead, implementing SmartLifecycle and moving the logic into start() is a better idea. The method may just throw an exception to fail the application run on startup.

Stuck
  • 11,225
  • 11
  • 59
  • 104