Skip to content

Commit 53a7f8d

Browse files
authored
fix(flex): defer swarm follower wait until after runtime build (#663)
Flex containers in SWARM_MODE=start the follower alongside the leader. The follower was blocking on the leader before cloning/building OpenEMR, so its Docker health start_period was consumed during the wait and then again during npm/composer—often exceeding the health check window and failing CI. - Introduce SWARM_WAIT_DEFERRED: followers skip wait_for_swarm_completion until after the local flex build block, then run wait + prepare_swarm_leader. - Split wait vs leader prep into wait_for_swarm_completion and prepare_swarm_leader for a clear call order. - Fix leader takeover checks: try_become_leader always returns 0, so gate promotion on AUTHORITY=yes instead of treating the return code as success. Tests: - Bats: assert_script_syntax on flex openemr.sh; smoke checks for swarm deferral. Validated with: bats tests/bats/flex/openemr.bats and ./utilities/container_benchmarking/test_functionality.sh flex --test swarm_mode Closes #661
1 parent 9aae18f commit 53a7f8d

2 files changed

Lines changed: 51 additions & 16 deletions

File tree

docker/openemr/flex/openemr.sh

Lines changed: 41 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,7 @@ is_configured() {
288288

289289
AUTHORITY=yes
290290
OPERATOR=yes
291+
SWARM_WAIT_DEFERRED=no
291292

292293
# Kubernetes-specific role assignment
293294
if [[ "${K8S}" = "admin" ]]; then
@@ -377,17 +378,8 @@ update_leader_heartbeat() {
377378
fi
378379
}
379380

380-
# Handles swarm mode coordination: leader election and follower waiting.
381-
handle_swarm_mode() {
382-
# Skip coordination if swarm mode isn't enabled
383-
if [[ "${SWARM_MODE}" != "yes" ]]; then
384-
return 0
385-
fi
386-
387-
# Try to become the leader
388-
try_become_leader
389-
390-
# If we're a follower, wait for the leader to finish setup
381+
# Waits for the swarm leader to finish setup before reading shared configuration.
382+
wait_for_swarm_completion() {
391383
if [[ "${AUTHORITY}" = "no" && ! -f "${OE_ROOT}/sites/docker-completed" ]]; then
392384
echo "Waiting for docker-leader to finish configuration (with timeout-based recovery)..."
393385
local -i max_wait_time="${LEADER_WAIT_TIMEOUT:-600}" # Default: 10 minutes
@@ -400,8 +392,8 @@ handle_swarm_mode() {
400392
# shellcheck disable=SC2310 # set -e behavior in conditionals is intentional
401393
if is_leader_stale; then
402394
echo "Leader appears to have crashed, attempting to take over..."
403-
# shellcheck disable=SC2310 # set -e behavior in conditionals is intentional
404-
if try_become_leader; then
395+
try_become_leader
396+
if [[ "${AUTHORITY}" = "yes" ]]; then
405397
echo "Successfully became leader after previous leader failure"
406398
break
407399
fi
@@ -412,8 +404,11 @@ handle_swarm_mode() {
412404

413405
# Try one more time to become leader (in case leader died just as we timed out)
414406
# shellcheck disable=SC2310 # set -e behavior in conditionals is intentional
415-
if [[ ! -f "${OE_ROOT}/sites/docker-completed" ]] && try_become_leader; then
416-
echo "Promoted to leader after waiting period"
407+
if [[ ! -f "${OE_ROOT}/sites/docker-completed" ]]; then
408+
try_become_leader
409+
if [[ "${AUTHORITY}" = "yes" ]]; then
410+
echo "Promoted to leader after waiting period"
411+
fi
417412
fi
418413

419414
# If we timed out, check if configuration actually exists
@@ -427,8 +422,10 @@ handle_swarm_mode() {
427422
fi
428423
fi
429424
fi
425+
}
430426

431-
# If we're the leader, create initiation marker and send heartbeat
427+
# If we're the leader, create initiation marker and restore swarm pieces.
428+
prepare_swarm_leader() {
432429
if [[ "${AUTHORITY}" = "yes" ]]; then
433430
touch "${OE_ROOT}/sites/docker-initiated"
434431
update_leader_heartbeat
@@ -445,6 +442,28 @@ handle_swarm_mode() {
445442
fi
446443
}
447444

445+
# Handles swarm mode coordination: leader election and follower waiting.
446+
handle_swarm_mode() {
447+
# Skip coordination if swarm mode isn't enabled
448+
if [[ "${SWARM_MODE}" != "yes" ]]; then
449+
return 0
450+
fi
451+
452+
# Try to become the leader
453+
try_become_leader
454+
455+
# Flex followers can prepare local source/dependencies while the leader
456+
# configures the shared sites volume, then wait before reading sqlconf.php.
457+
if [[ "${AUTHORITY}" = "no" && ! -f "${OE_ROOT}/sites/docker-completed" ]]; then
458+
SWARM_WAIT_DEFERRED=yes
459+
echo "Deferring docker-leader wait until local flex build is ready"
460+
return 0
461+
fi
462+
463+
wait_for_swarm_completion
464+
prepare_swarm_leader
465+
}
466+
448467
# ============================================================================
449468
# SWARM MODE COORDINATION (MAIN EXECUTION)
450469
# ============================================================================
@@ -687,6 +706,12 @@ if [[ "${NEED_COMPOSER_BUILD}" = "true" ]] || [[ "${NEED_NPM_BUILD}" = "true" ]]
687706
cd /var/www/localhost/htdocs
688707
fi
689708

709+
if [[ "${SWARM_WAIT_DEFERRED}" = "yes" ]]; then
710+
wait_for_swarm_completion
711+
SWARM_WAIT_DEFERRED=no
712+
prepare_swarm_leader
713+
fi
714+
690715
if [[ "${AUTHORITY}" = "yes" ]] ||
691716
[[ "${SWARM_MODE}" != "yes" ]]; then
692717
if [[ -f /var/www/localhost/htdocs/auto_configure.php ]] &&

tests/bats/flex/openemr.bats

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ setup() {
77
[[ -n "$SCRIPT_DIR" ]] && [[ -d "$SCRIPT_DIR" ]]
88
}
99

10+
@test "flex openemr.sh: valid bash syntax" {
11+
assert_script_syntax "${SCRIPT_DIR}/openemr.sh"
12+
}
13+
1014
@test "flex openemr.sh: FLEX_REPOSITORY and FLEX_REPOSITORY_BRANCH" {
1115
assert_script_contains "${SCRIPT_DIR}/openemr.sh" 'FLEX_REPOSITORY'
1216
assert_script_contains "${SCRIPT_DIR}/openemr.sh" 'FLEX_REPOSITORY_BRANCH'
@@ -35,6 +39,12 @@ setup() {
3539
assert_script_contains "${SCRIPT_DIR}/openemr.sh" 'SWARM_MODE='
3640
}
3741

42+
@test "flex openemr.sh: swarm follower defers leader wait for flex build" {
43+
assert_script_contains "${SCRIPT_DIR}/openemr.sh" 'SWARM_WAIT_DEFERRED=yes'
44+
assert_script_contains "${SCRIPT_DIR}/openemr.sh" 'Deferring docker-leader wait until local flex build is ready'
45+
assert_script_contains "${SCRIPT_DIR}/openemr.sh" 'wait_for_swarm_completion'
46+
}
47+
3848
@test "flex openemr.sh: INSANE_DEV_MODE or DEVELOPER_TOOLS" {
3949
assert_script_contains "${SCRIPT_DIR}/openemr.sh" 'EASY_DEV_MODE_NEW'
4050
grep -qE 'INSANE_DEV_MODE|DEVELOPER_TOOLS' "${SCRIPT_DIR}/openemr.sh"

0 commit comments

Comments
 (0)