Skip to content

Commit 3d202f0

Browse files
MatusBekeclaude
andcommitted
Give every service both recovery paths, and build the image instead of pulling
Two problems surfaced the first time this compose file was run end to end. 1. The stack did not start at all, and it had nothing to do with healthchecks. docker-compose.yml mounts ./dspace/config over the config inside the image, so the image has to be built from this tree. It is not enough to pull a matching version: this branch carries code no published image contains - for instance dspace/config/ehcache.xml references org.dspace.external.provider.orcid.xml.CacheLogger, which is in dspace-api here but in neither upstream 7.6.5 nor 7.6.8. A pulled image dies with "Error parsing XML configuration at file:/dspace/config/ehcache.xml", and before that with "Could not resolve placeholder 'pubmed.apiKey'". `docker compose up` builds a missing image on its own, so a clean machine never sees this. The trap is a stale image from an earlier pull silently shadowing the build, which makes the failure look like a config problem. DSPACE_VER is now pinned to the pom.xml version instead of the floating dspace-7_x tag so a newer upstream image cannot take its place, and the file says so in a comment. 2. Only the backend and the frontend could actually recover. dspacedb and dspacesolr had neither a restart policy nor the autoheal label, so "the database goes down and comes back on its own" simply did not happen - it stayed down. Every service now carries both, because they cover different failures: the restart policy handles a dead process and an exited container, the sidecar handles a container that still runs while its healthcheck fails. Verified by breaking each service in a different way: dspacedb pg_ctl stop -m immediate -> container exited, RestartCount 0 -> 1, back to healthy on its own dspacesolr search core unloaded -> failing streak 1..5 -> unhealthy -> restarted by the sidecar dspace chaos flag -> unhealthy -> restarted dspace-angular ng serve killed -> container exited -> restarted One correction to an earlier claim in this file: a restart does NOT repair an unloaded Solr core. precreate-core only checks whether the core directory exists, so it logs "Core search already exists" and leaves the core unregistered. The comment now says that, and it is precisely the case the sidecar's restart budget exists for - it gives up and asks for a human instead of looping. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1 parent 77102ad commit 3d202f0

2 files changed

Lines changed: 45 additions & 4 deletions

File tree

docker-compose.yml

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,24 @@
11
version: '3.7'
2+
# IMAGE VERSION - build it, do not pull it
3+
#
4+
# The dspace image MUST be built from this repository:
5+
#
6+
# docker compose build dspace
7+
#
8+
# This branch carries customisations that no published image contains. For example
9+
# dspace/config/ehcache.xml references org.dspace.external.provider.orcid.xml.CacheLogger,
10+
# which exists in dspace-api here but in neither upstream 7.6.5 nor 7.6.8. Since this
11+
# compose file also mounts ./dspace/config over the image config, a pulled image gives
12+
# you a newer/other webapp reading this tree config, and the DSpace kernel dies with
13+
# "Error parsing XML configuration at file:/dspace/config/ehcache.xml".
14+
#
15+
# `docker compose up` builds a missing image on its own, so a clean machine is fine.
16+
# The trap is a STALE image left over from an earlier pull: it shadows the build and
17+
# the failure looks unrelated to images. `docker compose build` is the fix.
18+
#
19+
# DSPACE_VER is pinned to the pom.xml version rather than the floating dspace-7_x tag
20+
# so the local build cannot be silently shadowed by a newer upstream one. Bump it
21+
# together with pom.xml.
222
networks:
323
dspacenet:
424
ipam:
@@ -46,7 +66,7 @@ services:
4666
# HeapDumpOnOutOfMemoryError writes the dump to the mounted log volume so the
4767
# cause survives the restart. Without it the restart destroys the evidence.
4868
JAVA_OPTS: '-Xmx2000m -XX:+ExitOnOutOfMemoryError -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/dspace/log'
49-
image: "${DOCKER_OWNER:-dspace}/dspace:${DSPACE_VER:-dspace-7_x-test}"
69+
image: "${DOCKER_OWNER:-dspace}/dspace:${DSPACE_VER:-dspace-7.6.5}-test"
5070
build:
5171
context: .
5272
dockerfile: Dockerfile.test
@@ -137,8 +157,16 @@ services:
137157
# DSpace PostgreSQL database container
138158
dspacedb:
139159
container_name: dspacedb
160+
# Two independent recovery paths, both needed:
161+
# restart policy -> the postmaster died and the container exited
162+
# autoheal label -> the container still runs but pg_isready keeps failing
163+
# Restarting a database is not free, which is why the sidecar enforces a restart
164+
# budget (3 per hour by default) and then stops and asks for a human.
165+
restart: unless-stopped
166+
labels:
167+
autoheal: "true"
140168
# Uses a custom Postgres image with pgcrypto installed
141-
image: "${DOCKER_OWNER:-dspace}/dspace-postgres-pgcrypto:${DSPACE_VER:-dspace-7_x}"
169+
image: "${DOCKER_OWNER:-dspace}/dspace-postgres-pgcrypto:${DSPACE_VER:-dspace-7.6.5}"
142170
build:
143171
# Must build out of subdirectory to have access to install script for pgcrypto
144172
context: ./dspace/src/main/docker/dspace-postgres-pgcrypto/
@@ -167,7 +195,19 @@ services:
167195
# DSpace Solr container
168196
dspacesolr:
169197
container_name: dspacesolr
170-
image: "${DOCKER_OWNER:-dspace}/dspace-solr:${DSPACE_VER:-dspace-7_x}"
198+
# Two independent recovery paths, both needed:
199+
# restart policy -> the Solr process died and the container exited
200+
# autoheal label -> the container still runs but the search core is gone
201+
#
202+
# Note what a restart does NOT fix: precreate-core only checks whether the core
203+
# DIRECTORY exists, so once a core has been unloaded (its core.properties is gone
204+
# but the directory stays) a restart logs "Core search already exists" and moves on,
205+
# leaving the core unregistered. That is intentional on the sidecar side - it burns
206+
# its restart budget, gives up, and asks for a human, which beats looping forever.
207+
restart: unless-stopped
208+
labels:
209+
autoheal: "true"
210+
image: "${DOCKER_OWNER:-dspace}/dspace-solr:${DSPACE_VER:-dspace-7.6.5}"
171211
build:
172212
context: ./dspace/src/main/docker/dspace-solr/
173213
# Provide path to Solr configs necessary to build Docker image

dspace/src/main/docker-compose/docker-compose-angular.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ networks:
1515
services:
1616
dspace-angular:
1717
container_name: dspace-angular
18+
restart: unless-stopped
1819
depends_on:
1920
dspace:
2021
condition: service_healthy
@@ -27,7 +28,7 @@ services:
2728
DSPACE_REST_HOST: localhost
2829
DSPACE_REST_PORT: 8080
2930
DSPACE_REST_NAMESPACE: /server
30-
image: dspace/dspace-angular:dspace-7_x
31+
image: "${DOCKER_OWNER:-dspace}/dspace-angular:${DSPACE_VER:-dspace-7.6.5}"
3132
ports:
3233
- published: 4000
3334
target: 4000

0 commit comments

Comments
 (0)