Skip to content

fix(ci): make memory-gate visible, fail loudly, stop starving roles_calculation - #170

Open
Oddly wants to merge 1 commit into
mainfrom
fix/ci-memory-gate-visibility
Open

fix(ci): make memory-gate visible, fail loudly, stop starving roles_calculation#170
Oddly wants to merge 1 commit into
mainfrom
fix/ci-memory-gate-visibility

Conversation

@Oddly

@Oddly Oddly commented Aug 4, 2026

Copy link
Copy Markdown
Owner

While chasing the post-outage "elasticsearch_roles_calculation" cancellations on #155, I ended up finding that the memory-based capacity gate was doing three things wrong in combination.

The retry loop in molecule/shared/create.yml is set to retries: 360, delay: 30, i.e. three hours. Every workflow that calls molecule.yml has a timeout in the 20-120 minute range, so a scenario that failed the memory check would silently retry until the workflow itself was killed. The user got a "The operation was canceled" message with zero context about what actually went wrong. Cutting retries to 30 means the task fails loudly after 15 minutes with the last "No capacity: X committed + Y needed > Z available" stdout, well inside the shortest workflow timeout.

Second, Ansible runs unbuffered through Python and GitHub Actions logs are not a TTY, so the FAILED - RETRYING (N retries left) messages sit in the stdout buffer and only flush when the buffer fills. On the two hangs I looked at, 73 retry lines all appeared at the same microsecond timestamp after roughly an hour of "silence." PYTHONUNBUFFERED=1 in the workflow env: fixes this so the retry chatter surfaces in real time.

Third, elasticsearch_roles_calculation asks for 4 × 4 GB = 16 GB even though its heap is 1 GB and the scenario only exercises the role-count calculation. Under peak concurrency the 16 GB request never won a slot against the 6-8 GB scenarios that kept flowing in and out. Halving each container to 2 GB drops the ask to 8 GB total, which clears the gate under the same load.

Together the three changes should turn "job cancelled after 45 minutes of silence" into either "runs green" or "fails loudly with a real error" — no more guessing which of the two is happening.

Summary by CodeRabbit

  • Bug Fixes
    • Improved visibility of Python and Ansible retry messages during automated checks.
    • Reduced memory allocation for Elasticsearch calculation and monitoring nodes to help prevent capacity and timeout issues.
    • Adjusted container startup retries to fail faster and align with workflow timeout limits.

…es_calculation

The molecule capacity-gate retry loop in shared/create.yml was set to
retries: 360 (3 hours) but the workflows that call it have timeouts of
20-120 minutes, so a starved scenario was always killed by the workflow
timeout before its own retries ran out. On top of that, Ansible's
FAILED - RETRYING messages sit in Python's stdout buffer under the
non-TTY GHA log, so the run looked like a silent hang for 45+ minutes
before the last cancel showed up. Between them, a queue-starvation
event and a genuinely broken scenario were impossible to tell apart.

Cap retries at 30 (= 15 min) so the task fails loudly with the last
'No capacity: X committed + Y needed > Z available' stdout, well inside
every workflow's timeout. Set PYTHONUNBUFFERED=1 in the molecule
workflow env so the retry chatter surfaces in real time.

Also shrink the four elasticsearch_roles_calculation containers from
4 GB to 2 GB each (16 GB -> 8 GB). elasticsearch_heap is 1 GB and the
scenario only exercises the role-calculation code path, so 2 GB is
plenty of headroom. Halving the memory ask is what lets the scenario
clear the gate under peak concurrency instead of retrying until the
workflow timeout.
@Oddly Oddly added the ci:run Trigger gated pull request CI label Aug 4, 2026
@Oddly
Oddly enabled auto-merge (squash) August 4, 2026 07:12
@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Molecule CI now uses unbuffered Python output, lower memory allocations for the Elasticsearch calculation scenario, and a 15-minute container launch retry window.

Changes

Molecule CI tuning

Layer / File(s) Summary
Scenario memory allocation
molecule/elasticsearch_roles_calculation/molecule.yml
The three Elasticsearch nodes and monitoring node now use 2048 MB each instead of 4096 MB.
Launch retry and output diagnostics
.github/workflows/molecule.yml, molecule/shared/create.yml
The workflow enables PYTHONUNBUFFERED. Container launch retries now run 30 times with a 30-second delay.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the CI retry, logging, and memory changes in the pull request.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/ci-memory-gate-visibility

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot removed the ci:run Trigger gated pull request CI label Aug 4, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@molecule/elasticsearch_roles_calculation/molecule.yml`:
- Around line 19-37: Update the elasticsearch_roles_calculation reservation in
scripts/wait-for-memory.sh to 8192 MB, matching the four 2048 MB Molecule
platforms defined in molecule.yml; preferably derive the value from the Molecule
configuration to prevent future drift.

In `@molecule/shared/create.yml`:
- Around line 129-138: The retry configuration around _launch_result must
enforce a true elapsed-time limit rather than relying only on retries and delay.
Update the launch command’s flock wait budget or add a deadline so lock
contention cannot extend the task toward the workflow timeout, while preserving
the existing retry behavior and ensuring the total standard-workflow duration
remains within the intended 15-minute guard.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 15bb8583-1ed8-4db7-bbef-6dab38c5c6b1

📥 Commits

Reviewing files that changed from the base of the PR and between b305444 and 7d044ad.

📒 Files selected for processing (3)
  • .github/workflows/molecule.yml
  • molecule/elasticsearch_roles_calculation/molecule.yml
  • molecule/shared/create.yml

Comment on lines +19 to +37
memory_mb: 2048
- name: "es-calc2-${MOLECULE_DISTRO:-debian12}-r${ELASTIC_RELEASE:-9}${MOLECULE_RUN_SUFFIX}"
groups:
- elasticsearch
distro: "${MOLECULE_DISTRO:-debian12}"
memory_mb: 4096
memory_mb: 2048
- name: "es-calc3-${MOLECULE_DISTRO:-debian12}-r${ELASTIC_RELEASE:-9}${MOLECULE_RUN_SUFFIX}"
groups:
- elasticsearch
distro: "${MOLECULE_DISTRO:-debian12}"
memory_mb: 4096
memory_mb: 2048
# Separate single-node "monitoring" cluster, run in a second play against
# this group to catch the regression from #143 where group_by accumulated
# elasticsearch_role_master across plays.
- name: "es-calc-mon-${MOLECULE_DISTRO:-debian12}-r${ELASTIC_RELEASE:-9}${MOLECULE_RUN_SUFFIX}"
groups:
- elasticsearch_mon
distro: "${MOLECULE_DISTRO:-debian12}"
memory_mb: 4096
memory_mb: 2048

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚀 Performance & Scalability | 🟠 Major | ⚡ Quick win

Synchronize the capacity reservation with the new total.

These four platforms now request 4 * 2048 = 8192 MB. However, scripts/wait-for-memory.sh:43-59 still reserves 16384 MB for elasticsearch_roles_calculation. The workflow uses that reservation before molecule converge, so the scenario can remain queued as a 16 GB job and the intended capacity-gate improvement is not achieved.

Update the reservation to 8192 MB, or derive it from the Molecule configuration to prevent drift.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@molecule/elasticsearch_roles_calculation/molecule.yml` around lines 19 - 37,
Update the elasticsearch_roles_calculation reservation in
scripts/wait-for-memory.sh to 8192 MB, matching the four 2048 MB Molecule
platforms defined in molecule.yml; preferably derive the value from the Molecule
configuration to prevent future drift.

Comment on lines +129 to 138
# 30 retries × 30s = 15 min. Deliberately shorter than the workflow
# timeout (45 min for the standard molecule.yml call, 120 min for
# full_stack) so the task fails loudly with the last "No capacity:
# …" stdout instead of being silently cancelled by the workflow
# timeout — that made the queue-starvation cases very hard to
# diagnose (see PR investigating the elasticsearch_roles_calculation
# / elasticstack_default post-outage hangs).
retries: 30
delay: 30
until: _launch_result.rc == 0

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Files matching molecule/shared/create.yml:"
git ls-files | grep -Fx 'molecule/shared/create.yml' || true

echo
echo "Context around create.yml lines 60-150:"
if [ -f molecule/shared/create.yml ]; then
  nl -ba molecule/shared/create.yml | sed -n '60,160p'
fi

echo
echo "Search workflow timeout mentions:"
rg -n "45 min|120 min|timeout|full_stack|molecule.yml|retry|delay|flock -x -w 60|_launch_result" molecule .github 2>/dev/null || true

Repository: Oddly/elasticstack

Length of output: 308


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Context around molecule/shared/create.yml lines 60-150:"
awk '{printf "%6d\t%s\n", NR, $0}' molecule/shared/create.yml | sed -n '60,150p'

echo
echo "Context around launch/flock tasks and retries/delay:"
awk '{printf "%6d\t%s\n", NR, $0}' molecule/shared/create.yml | sed -n '1,180p'

echo
echo "Search workflow timeout mentions:"
rg -n "45 min|120 min|timeout|full_stack|molecule.yml|retry|delay|flock -x -w 60|_launch_result|molecule/shared/create.yml" molecule .github 2>/dev/null || true

Repository: Oddly/elasticstack

Length of output: 27420


Bound the retry window by elapsed time.

retries: 30 and delay: 30 count attempts and inter-attempt waits, but the command can also wait up to 60 seconds at flock -x -w 60 each time. Under lock contention, this task can run close to 45 minutes before Ansible gives up, which defeats the 15-minute guard for the standard workflow. Use an elapsed-time deadline, or reduce the lock/wait budget so the total time stays below the workflow timeout.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@molecule/shared/create.yml` around lines 129 - 138, The retry configuration
around _launch_result must enforce a true elapsed-time limit rather than relying
only on retries and delay. Update the launch command’s flock wait budget or add
a deadline so lock contention cannot extend the task toward the workflow
timeout, while preserving the existing retry behavior and ensuring the total
standard-workflow duration remains within the intended 15-minute guard.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant