httpd/koji: set MaxKeepAliveRequests 0 to fix 502 race condition #3213

Merged
kevin merged 2 commits from victorkoycheff/ansible:issue-12913-koji-502 into main 2026-04-30 00:54:15 +00:00
Contributor

This PR is the second (and final) half of the fix for the Koji 502 Bad Gateway errors reported in #12913.

What was happening:
My previous PR (#3173) added ttl=10 to the proxyopts. That successfully fixed the idle timeout race condition, but people were still occasionally hitting 502s under heavy load.

Turns out there was a second race condition at play: the request count limit. The backend Apache configurations (httpd.conf.j2, kojiweb.conf.j2) had MaxKeepAliveRequests 500 hardcoded. If a client polled aggressively enough (bypassing the 10-second idle TTL), the proxy would reuse the same connection until it hit exactly 500 requests. At that moment, the backend Apache server would ruthlessly close the TCP connection. If the proxy tried to hand off request #501 at that exact millisecond, we'd get a 502.

The Fix:
This PR sets MaxKeepAliveRequests 0 (unlimited) on the proxy and Koji hub/web templates.
By removing the request limit on the backend, we ensure the backend never hangs up on the proxy unexpectedly. The ttl=10 setting from the previous PR remains in place and now functions perfectly as the sole lifecycle manager for these connections, gracefully closing them only when they are genuinely idle.

Testing:
I verified this locally using a Python script built to spam the hello endpoint. Without this fix, the script reliably hits a 502 between 500-1500 requests.

Fixes #12913

This PR is the second (and final) half of the fix for the Koji 502 Bad Gateway errors reported in #12913. **What was happening:** My previous PR (#3173) added `ttl=10` to the proxyopts. That successfully fixed the *idle timeout* race condition, but people were still occasionally hitting 502s under heavy load. Turns out there was a second race condition at play: the **request count limit**. The backend Apache configurations (`httpd.conf.j2`, `kojiweb.conf.j2`) had `MaxKeepAliveRequests 500` hardcoded. If a client polled aggressively enough (bypassing the 10-second idle TTL), the proxy would reuse the same connection until it hit exactly 500 requests. At that moment, the backend Apache server would ruthlessly close the TCP connection. If the proxy tried to hand off request #501 at that exact millisecond, we'd get a 502. **The Fix:** This PR sets `MaxKeepAliveRequests 0` (unlimited) on the proxy and Koji hub/web templates. By removing the request limit on the backend, we ensure the backend never hangs up on the proxy unexpectedly. The `ttl=10` setting from the previous PR remains in place and now functions perfectly as the *sole* lifecycle manager for these connections, gracefully closing them only when they are genuinely idle. **Testing:** I verified this locally using a Python script built to spam the `hello` endpoint. Without this fix, the script reliably hits a 502 between 500-1500 requests. Fixes #12913
proxies-reverseproxy: set keepalive=on ttl=10 for koji
Some checks failed
Linter / yamllint (pull_request) Failing after 29s
Linter / ansible-lint (pull_request) Failing after 30s
AI Code Review / ai-review (pull_request_target) Successful in 29s
947cfd0b2c
This fixes intermittent 502 Bad Gateway errors during long-running
koji connections (like watch-task or watch-logs).

For more details on proxy keepalive and ttl, see:
https://httpd.apache.org/docs/2.4/mod/mod_proxy.html

Fixes #12913

Signed-off-by: Victor Koycheff <victorkoycheff@gmail.com>
victorkoycheff force-pushed issue-12913-koji-502 from cd59b81cfc
Some checks failed
Linter / yamllint (pull_request) Failing after 26s
Linter / ansible-lint (pull_request) Failing after 30s
to c686b58853
All checks were successful
Linter / yamllint (pull_request) Successful in 26s
Linter / ansible-lint (pull_request) Successful in 41s
2026-03-12 20:40:44 +00:00
Compare
Owner

So, I am not convinced that this will fix the underlying issue.

However, I am willing to give it a try now that we are out of freeze.

So, I am not convinced that this will fix the underlying issue. However, I am willing to give it a try now that we are out of freeze.
kevin merged commit e56db32aa6 into main 2026-04-30 00:54:15 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
infra/ansible!3213
No description provided.