Skip to content

Comments

fix: Prevent infinite loop in repository configuration on failures#896

Merged
myakove merged 3 commits intomainfrom
fix/repository-settings-infinite-loop
Nov 10, 2025
Merged

fix: Prevent infinite loop in repository configuration on failures#896
myakove merged 3 commits intomainfrom
fix/repository-settings-infinite-loop

Conversation

@myakove
Copy link
Collaborator

@myakove myakove commented Nov 10, 2025

Fixed critical bug in get_future_results() where calling result.result() before checking for exceptions would crash the entire process when encountering failed repositories (e.g., archived repos).

The crash would trigger auto-restart (Docker/systemd), creating an infinite crash-restart loop that prevented any repositories from being configured.

Changes:

  • Check for exceptions using try-except BEFORE calling result.result()
  • Use logger.exception() for proper traceback capture
  • Continue processing remaining repositories on individual failures
  • Improved error message with actionable guidance

Fixes: Archon task 3f6a599b-7d4d-4626-9b72-d367c525060e

Summary by CodeRabbit

  • Bug Fixes

    • Improved error handling for concurrent tasks so individual failures no longer disrupt processing and full error context is preserved.
  • Documentation

    • Expanded docstrings and inline notes describing the improved failure handling and logging behavior.
  • Tests

    • Updated tests to exercise exception paths, verify logging behavior, and to ignore unused third return values in various assertions.
  • Chores

    • Enabled an additional lint rule in project configuration.
  • Behavior

    • Minor error-message formatting adjusted for consistent exception text.

Fixed critical bug in get_future_results() where calling result.result()
before checking for exceptions would crash the entire process when
encountering failed repositories (e.g., archived repos).

The crash would trigger auto-restart (Docker/systemd), creating an
infinite crash-restart loop that prevented any repositories from being
configured.

Changes:
- Check for exceptions using try-except BEFORE calling result.result()
- Use logger.exception() for proper traceback capture
- Continue processing remaining repositories on individual failures
- Improved error message with actionable guidance

Fixes: Archon task 3f6a599b-7d4d-4626-9b72-d367c525060e
@coderabbitai
Copy link

coderabbitai bot commented Nov 10, 2025

Walkthrough

get_future_results in webhook_server/utils/helpers.py now iterates over futures with concurrent.futures.as_completed, wraps each future.result() call in try/except and logs exceptions with logger.exception. Docstring/comments updated and tests adjusted to exercise the exception path.

Changes

Cohort / File(s) Summary
Helpers — future processing & docs
webhook_server/utils/helpers.py
Rewrote get_future_results() to iterate with as_completed, catch exceptions around future.result(), call returned logger_func on success, and use logger.exception() with a global message on failures. Expanded docstring and inline comments (CRITICAL FIX note).
Tests — helpers & exception behavior
webhook_server/tests/test_helpers.py, webhook_server/tests/test_helpers_sanitization.py
Updated test futures to raise in result() for exception path; patched as_completed to yield futures; adjusted unpacking to ignore third return values where applicable; added assertions for logger.exception() and maintained success-path logging checks.
Tests — runner & webhook adjustments
webhook_server/tests/test_runner_handler.py, webhook_server/tests/test_webhook.py, webhook_server/tests/test_edge_cases_validation.py
Replaced several unpackings to discard third return value (err_), and simplified filter checks to use filter_params.get(...) truthiness. Minor behavioral alignment in tests.
Config — linter rules
pyproject.toml
Added RUF059 to Ruff lint select list.
Utils — error formatting
webhook_server/utils/app_utils.py
Adjusted error-string formatting in parse_datetime_string to use {e!s} instead of str(e).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Review the try/except scope in get_future_results() to ensure exceptions are logged with preserved traceback and no unrelated errors are suppressed.
  • Verify the tuple contract (success, message, logger_func) is still respected and invoked consistently on success.
  • Confirm tests correctly simulate and assert the exception logging behavior and that changed unpacking doesn't hide important assertions.
  • Quick lint config check for intended Ruff rule addition.

Suggested reviewers

  • rnetser

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 75.76% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix: Prevent infinite loop in repository configuration on failures' directly describes the main change—fixing a critical bug that caused infinite crash-restart loops by adding exception handling to get_future_results().
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/repository-settings-infinite-loop

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 68f723b and a03a47b.

📒 Files selected for processing (7)
  • pyproject.toml (1 hunks)
  • webhook_server/tests/test_edge_cases_validation.py (1 hunks)
  • webhook_server/tests/test_helpers_sanitization.py (2 hunks)
  • webhook_server/tests/test_runner_handler.py (12 hunks)
  • webhook_server/tests/test_webhook.py (10 hunks)
  • webhook_server/utils/app_utils.py (1 hunks)
  • webhook_server/utils/helpers.py (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • webhook_server/tests/test_runner_handler.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • webhook_server/utils/helpers.py
🧰 Additional context used
🧠 Learnings (7)
📓 Common learnings
Learnt from: myakove
Repo: myk-org/github-webhook-server PR: 612
File: webhook_server_container/libs/github_api.py:2089-2100
Timestamp: 2024-10-29T08:09:57.157Z
Learning: In `webhook_server_container/libs/github_api.py`, when the function `_keep_approved_by_approvers_after_rebase` is called, existing approval labels have already been cleared after pushing new changes, so there's no need to check for existing approvals within this function.
Learnt from: myakove
Repo: myk-org/github-webhook-server PR: 612
File: webhook_server_container/libs/github_api.py:925-926
Timestamp: 2024-10-29T10:42:50.163Z
Learning: In `webhook_server_container/libs/github_api.py`, the method `self._keep_approved_by_approvers_after_rebase()` must be called after removing labels when synchronizing a pull request. Therefore, it should be placed outside the `ThreadPoolExecutor` to ensure it runs sequentially after label removal.
📚 Learning: 2024-10-15T10:37:45.791Z
Learnt from: myakove
Repo: myk-org/github-webhook-server PR: 598
File: webhook_server_container/libs/github_api.py:1860-1874
Timestamp: 2024-10-15T10:37:45.791Z
Learning: In the `process_retest_command` method in `webhook_server_container/libs/github_api.py`, `_target_tests` is defined before use.

Applied to files:

  • webhook_server/tests/test_webhook.py
  • webhook_server/tests/test_helpers_sanitization.py
📚 Learning: 2024-11-26T14:30:22.906Z
Learnt from: myakove
Repo: myk-org/github-webhook-server PR: 631
File: webhook_server_container/tests/test_github_api.py:321-327
Timestamp: 2024-11-26T14:30:22.906Z
Learning: In `webhook_server_container/tests/test_github_api.py`, when using `pytest.mark.parametrize` with indirect parameters, the `pytest.param` function may require nested lists to match the expected input structure.

Applied to files:

  • webhook_server/tests/test_webhook.py
  • webhook_server/tests/test_edge_cases_validation.py
📚 Learning: 2024-10-14T14:13:21.316Z
Learnt from: myakove
Repo: myk-org/github-webhook-server PR: 588
File: webhook_server_container/libs/github_api.py:1632-1637
Timestamp: 2024-10-14T14:13:21.316Z
Learning: In the `ProcessGithubWehook` class in `webhook_server_container/libs/github_api.py`, avoid using environment variables to pass tokens because multiple commands with multiple tokens can run at the same time.

Applied to files:

  • webhook_server/tests/test_webhook.py
📚 Learning: 2024-10-09T09:16:45.452Z
Learnt from: myakove
Repo: myk-org/github-webhook-server PR: 579
File: webhook_server_container/libs/github_api.py:1098-1101
Timestamp: 2024-10-09T09:16:45.452Z
Learning: In the Python method `_run_tox` within `webhook_server_container/libs/github_api.py`, the variable `_tox_tests` is already comma-separated, so removing spaces with `_tox_tests.replace(" ", "")` is appropriate to handle any accidental spaces when specifying Tox environments.

Applied to files:

  • webhook_server/tests/test_webhook.py
  • webhook_server/tests/test_helpers_sanitization.py
📚 Learning: 2024-10-29T08:09:57.157Z
Learnt from: myakove
Repo: myk-org/github-webhook-server PR: 612
File: webhook_server_container/libs/github_api.py:2089-2100
Timestamp: 2024-10-29T08:09:57.157Z
Learning: In `webhook_server_container/libs/github_api.py`, when the function `_keep_approved_by_approvers_after_rebase` is called, existing approval labels have already been cleared after pushing new changes, so there's no need to check for existing approvals within this function.

Applied to files:

  • webhook_server/tests/test_webhook.py
  • webhook_server/tests/test_edge_cases_validation.py
📚 Learning: 2024-10-14T14:12:28.924Z
Learnt from: myakove
Repo: myk-org/github-webhook-server PR: 588
File: webhook_server_container/libs/github_api.py:1638-1639
Timestamp: 2024-10-14T14:12:28.924Z
Learning: In `webhook_server_container/libs/github_api.py`, it is acceptable for `self.repository.owner.email` to be `None` since internal commands can handle this case.

Applied to files:

  • webhook_server/tests/test_webhook.py
🧬 Code graph analysis (2)
webhook_server/tests/test_webhook.py (1)
webhook_server/utils/webhook.py (1)
  • process_github_webhook (17-69)
webhook_server/tests/test_helpers_sanitization.py (1)
webhook_server/utils/helpers.py (1)
  • run_command (266-374)
🔇 Additional comments (5)
pyproject.toml (1)

18-18: LGTM! Enabling RUF059 improves code quality.

Adding the RUF059 lint rule helps detect unnecessary key checks that can be simplified to truthiness checks, which aligns with the refactoring changes in this PR.

webhook_server/tests/test_webhook.py (1)

45-45: LGTM! Consistent pattern for discarding unused logger function.

The tests now consistently discard the third return value (logger function) from process_github_webhook using _. This is appropriate since the tests focus on verifying the success status and message content rather than the logger function reference.

Also applies to: 73-73, 103-103, 132-132, 163-163, 207-207, 237-237, 252-252, 273-273, 302-302

webhook_server/utils/app_utils.py (1)

118-118: LGTM! More explicit string conversion.

Using {e!s} instead of {str(e)} is a cleaner, more idiomatic way to convert the exception to a string in an f-string.

webhook_server/tests/test_edge_cases_validation.py (1)

551-554: LGTM! Simplified conditional logic.

The change from explicit key presence checks to truthiness-based checks using .get() is cleaner and more Pythonic. This aligns with the RUF059 lint rule enabled in this PR.

webhook_server/tests/test_helpers_sanitization.py (1)

382-382: LGTM! Discarding unused stderr return value.

The tests appropriately discard the stderr return value using _ since these tests only need to verify the stdout content and success status. This is consistent with the broader pattern of simplifying test code in this PR.

Also applies to: 414-414


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 and usage tips.

@myakove-bot
Copy link
Collaborator

Report bugs in Issues

Welcome! 🎉

This pull request will be automatically processed with the following features:

🔄 Automatic Actions

  • Reviewer Assignment: Reviewers are automatically assigned based on the "
    "OWNERS file in the repository root
    "
    "* Size Labeling: PR size labels (XS, S, M, L, XL, XXL) are "
    "automatically applied based on changes
    "
    f"* Issue Creation: A tracking issue is created for this PR and will be closed when the PR is merged or closed
    "
    "* Pre-commit Checks: pre-commit runs "
    "automatically if .pre-commit-config.yaml exists
    "
  • Branch Labeling: Branch-specific labels are applied to track the target branch
  • Auto-verification: Auto-verified users have their PRs automatically marked as verified

📋 Available Commands

PR Status Management

  • /wip - Mark PR as work in progress (adds WIP: prefix to title)
  • /wip cancel - Remove work in progress status
  • /hold - Block PR merging (approvers only)
  • /hold cancel - Unblock PR merging
  • /verified - Mark PR as verified
  • /verified cancel - Remove verification status
  • /reprocess - Trigger complete PR workflow reprocessing (useful if webhook failed or configuration changed)

Review & Approval

  • /lgtm - Approve changes (looks good to me)
  • /approve - Approve PR (approvers only)
  • /automerge - Enable automatic merging when all requirements are met (maintainers and approvers only)
  • /assign-reviewers - Assign reviewers based on OWNERS file
  • /assign-reviewer @username - Assign specific reviewer
  • /check-can-merge - Check if PR meets merge requirements

Testing & Validation

  • /retest tox - Run Python test suite with tox
  • /retest build-container - Rebuild and test container image
  • /retest python-module-install - Test Python package installation
  • /retest pre-commit - Run pre-commit hooks and checks
  • /retest conventional-title - Validate commit message format
  • /retest all - Run all available tests

Container Operations

  • /build-and-push-container - Build and push container image (tagged with PR number)
    • Supports additional build arguments: /build-and-push-container --build-arg KEY=value

Cherry-pick Operations

  • /cherry-pick <branch> - Schedule cherry-pick to target branch when PR is merged
    • Multiple branches: /cherry-pick branch1 branch2 branch3

Label Management

  • /<label-name> - Add a label to the PR
  • /<label-name> cancel - Remove a label from the PR

✅ Merge Requirements

This PR will be automatically approved when the following conditions are met:

  1. Approval: /approve from at least one approver
  2. LGTM Count: Minimum 1 /lgtm from reviewers
  3. Status Checks: All required status checks must pass
  4. No Blockers: No WIP, hold, or conflict labels
  5. Verified: PR must be marked as verified (if verification is enabled)

📊 Review Process

Approvers and Reviewers

Approvers:

  • myakove
  • rnetser

Reviewers:

  • myakove
  • rnetser
Available Labels
  • hold
  • verified
  • wip
  • lgtm
  • approve
  • automerge

💡 Tips

  • WIP Status: Use /wip when your PR is not ready for review
  • Verification: The verified label is automatically removed on each new commit
  • Cherry-picking: Cherry-pick labels are processed when the PR is merged
  • Container Builds: Container images are automatically tagged with the PR number
  • Permission Levels: Some commands require approver permissions
  • Auto-verified Users: Certain users have automatic verification and merge privileges

For more information, please refer to the project documentation or contact the maintainers.

@myakove
Copy link
Collaborator Author

myakove commented Nov 10, 2025

/verified
/approve

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
webhook_server/utils/helpers.py (1)

482-496: Critical fix correctly implemented! Exception handling prevents the crash-restart loop.

The try/except wrapper around result.result() properly catches exceptions from failed futures, and logger.exception() captures full tracebacks. The loop continues processing remaining repositories, which is exactly the desired resilience behavior.

Optional: Consider more explicit tuple unpacking for readability.

Current implementation at lines 488-490:

_res = result.result()
_log = _res[2]
_log(_res[1])

Could be slightly clearer as:

success, message, log_func = result.result()
log_func(message)

This makes the tuple structure more obvious, though the current approach is perfectly fine.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bf6052d and 7e22e21.

📒 Files selected for processing (1)
  • webhook_server/utils/helpers.py (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
webhook_server/utils/helpers.py (2)
webhook_server/tests/test_github_api.py (1)
  • logger (74-75)
webhook_server/tests/test_helpers.py (6)
  • result (299-300)
  • result (310-311)
  • result (321-322)
  • exception (302-303)
  • exception (313-314)
  • exception (324-325)
🔇 Additional comments (1)
webhook_server/utils/helpers.py (1)

471-481: LGTM! Clear documentation of exception handling behavior.

The expanded docstring effectively communicates the new resilience behavior and provides helpful context about potential failure scenarios.

- Fix DummyFutureException to properly raise exceptions in tests
- Add assertions to verify exception handling works correctly
- Improve tuple unpacking readability (success, message, logger_func)

Addresses CodeRabbit review comments on fix/repository-settings-infinite-loop
@myakove
Copy link
Collaborator Author

myakove commented Nov 10, 2025

/verified
/approve

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
webhook_server/utils/helpers.py (1)

484-494: Exception handling fix is correct, but unused variable can be optimized.

The try-except block properly catches exceptions from result.result() and logs them with full traceback context via logger.exception(). The loop continues processing remaining futures, which prevents the infinite crash-restart loop described in the PR objectives.

However, the success variable on line 488 is unpacked but never used. Consider using tuple unpacking with underscore:

-            success, message, logger_func = result.result()
+            _success, message, logger_func = result.result()

Or if the success value might be needed for future enhancements:

-            success, message, logger_func = result.result()
+            success, message, logger_func = result.result()  # noqa: RUF059
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7e22e21 and 68f723b.

📒 Files selected for processing (2)
  • webhook_server/tests/test_helpers.py (1 hunks)
  • webhook_server/utils/helpers.py (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: myakove
Repo: myk-org/github-webhook-server PR: 612
File: webhook_server_container/libs/github_api.py:2089-2100
Timestamp: 2024-10-29T08:09:57.157Z
Learning: In `webhook_server_container/libs/github_api.py`, when the function `_keep_approved_by_approvers_after_rebase` is called, existing approval labels have already been cleared after pushing new changes, so there's no need to check for existing approvals within this function.
Learnt from: myakove
Repo: myk-org/github-webhook-server PR: 612
File: webhook_server_container/libs/github_api.py:925-926
Timestamp: 2024-10-29T10:42:50.163Z
Learning: In `webhook_server_container/libs/github_api.py`, the method `self._keep_approved_by_approvers_after_rebase()` must be called after removing labels when synchronizing a pull request. Therefore, it should be placed outside the `ThreadPoolExecutor` to ensure it runs sequentially after label removal.
Learnt from: myakove
Repo: myk-org/github-webhook-server PR: 586
File: webhook_server_container/libs/github_api.py:1947-1956
Timestamp: 2024-10-08T09:19:56.185Z
Learning: In `webhook_server_container/libs/github_api.py`, the indentation style used in the `set_pull_request_automerge` method is acceptable as per the project's coding standards.
🧬 Code graph analysis (2)
webhook_server/utils/helpers.py (1)
webhook_server/tests/test_helpers.py (6)
  • result (299-300)
  • result (310-311)
  • result (321-322)
  • exception (302-303)
  • exception (313-314)
  • exception (324-325)
webhook_server/tests/test_helpers.py (1)
webhook_server/utils/helpers.py (1)
  • get_future_results (471-494)
🪛 Ruff (0.14.3)
webhook_server/utils/helpers.py

488-488: Unpacked variable success is never used

Prefix it with an underscore or any other dummy variable pattern

(RUF059)

webhook_server/tests/test_helpers.py

322-322: Avoid specifying long messages outside the exception class

(TRY003)

🔇 Additional comments (4)
webhook_server/tests/test_helpers.py (2)

319-328: Excellent fix for the test mock!

The DummyFutureException class now correctly simulates concurrent.futures.Future behavior by raising the exception from result() instead of returning a tuple. This addresses the previous review concern and ensures the exception handling path in get_future_results is properly exercised.


331-348: Test coverage is now comprehensive.

The test properly validates the exception handling path by:

  1. Verifying logger.exception is called with the correct message
  2. Confirming that processing continues for remaining futures (success and fail futures have their messages logged)
  3. Ensuring the exception future doesn't set a log attribute (as expected when exception is raised)

This fully addresses the concerns raised in the previous review.

webhook_server/utils/helpers.py (2)

471-481: Well-documented behavioral change.

The updated docstring clearly explains that the function handles partial failures gracefully and continues processing on exceptions. The notes about worker thread crashes on archived repositories or API permission issues provide helpful context.


482-482: Logger initialization is appropriate.

Creating a shared logger for all exception logging is the correct approach, ensuring consistent logging behavior across all repository configuration tasks.

Fixed all 36 RUF059 linting errors by replacing unused variables in
tuple unpacking with '_' placeholder. This improves code clarity by
explicitly marking values that are intentionally ignored.

Changes:
- Updated test files to use '_' for unused tuple values
- Enabled RUF059 rule in pyproject.toml to prevent future violations
- Improved helper functions to discard unused return values
- Applied .get() pattern in edge case validation

Affected files:
- pyproject.toml: Added RUF059 to linting rules
- test_helpers_sanitization.py: 2 fixes (stderr unused)
- test_runner_handler.py: 20 fixes (rc/out/err unused)
- test_webhook.py: 10 fixes (message/log_func unused)
- test_edge_cases_validation.py: 2 fixes (dict.get pattern)
- helpers.py: 1 fix (success unused)
- app_utils.py: 1 fix (str() to \!s conversion)
@myakove
Copy link
Collaborator Author

myakove commented Nov 10, 2025

/verified
/approve

@myakove myakove merged commit 4439ff4 into main Nov 10, 2025
8 of 9 checks passed
@myakove myakove deleted the fix/repository-settings-infinite-loop branch November 10, 2025 13:55
@myakove-bot
Copy link
Collaborator

New container for ghcr.io/myk-org/github-webhook-server:latest published

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants