How the Proxy Backoff Algorithm Handles a Complete Proxy Pool Failure in biliTickerBuy
The ProxyBackoff class implements an exponential backoff capped at 600 seconds, delivering a single user notification while continuing to retry until the proxy pool recovers.
The biliTickerBuy repository is an open-source ticket purchasing automation tool that relies heavily on proxy pools to distribute requests. When every proxy in the pool becomes unavailable simultaneously—a complete proxy pool failure—the application must avoid crashing or hammering dead services while maintaining purchase attempts.
Core Implementation in the ProxyBackoff Class
The proxy backoff algorithm is encapsulated in util/proxy/ProxyBackoff.py. This class is instantiated for each buying session in task/buy.py and manages the timing and user notifications when proxy requests fail consecutively.
Exponential Delay Growth
The algorithm calculates the next retry delay using exponential growth bounded by a maximum ceiling. The implementation in next_delay_seconds() follows this logic:
delay = int(round(self.base_seconds * (self.factor ** self.exhausted_rounds)))
self.exhausted_rounds += 1
return min(delay, self.max_seconds)
The parameters are configurable:
- base_seconds: Starting delay, defaulting to 30 seconds
- factor: Multiplier applied after each failure, fixed at 2.0
- max_seconds: Upper ceiling for delays, defaulting to 600 seconds (10 minutes)
This means the first failure waits ~30 seconds, the second waits ~60 seconds, the third ~120 seconds, and so on, until hitting the 600-second cap.
Reset on Success
When a request finally succeeds after obtaining a fresh proxy, the calling code invokes proxy_backoff.reset() (called from task/buy_helpers.py). This method clears the exhausted_rounds counter and the internal notification flag, restoring the backoff to its initial state and allowing immediate rapid retries for subsequent requests.
Single-Shot Notification
The should_notify() method returns True only the first time it is called after a failure series begins. This ensures the UI displays a "all proxies failed" warning exactly once per outage cycle, preventing log spam or repetitive alerts while the system continues its backoff loop.
Integration with the Buying Workflow
In the main buying loop (found in task/buy_helpers.py), the algorithm integrates with request handling through a consistent pattern:
delay_seconds = proxy_backoff.next_delay_seconds()
if proxy_backoff.should_notify():
# Trigger UI warning: "All proxies are currently unavailable"
time.sleep(delay_seconds)
When a complete proxy pool failure occurs, this integration ensures the application:
- Continues retrying after increasingly longer sleeps (capped at
max_seconds) - Warns the user exactly once via the UI or logs
- Avoids overwhelming dead proxy services with rapid reconnection attempts
Configuration and Defaults
The configurable limits are defined in interface/config.py, where proxy_backoff_max_seconds defaults to 600 seconds. Users can adjust base_seconds and max_seconds when instantiating the ProxyBackoff class to match their specific proxy pool recovery characteristics or network conditions.
Practical Usage Example
The following pattern demonstrates how to implement the proxy backoff algorithm in custom polling logic:
from util.proxy.ProxyBackoff import ProxyBackoff
import time
# Initialize with custom limits
backoff = ProxyBackoff(base_seconds=20, factor=2.0, max_seconds=300)
while True:
try:
response = send_request_via_proxy()
backoff.reset() # Clear counters on success
break
except ProxyError:
wait = backoff.next_delay_seconds()
if backoff.should_notify():
print("⚠️ All proxies are currently unavailable.")
print(f"Retrying in {wait} seconds...")
time.sleep(wait)
This pattern mirrors the production implementation in task/buy_helpers.py, ensuring graceful degradation during total proxy outages.
Summary
- The
ProxyBackoffclass inutil/proxy/ProxyBackoff.pyprovides exponential backoff with configurable base delay (30s default) and maximum cap (600s default). - Delays double after each consecutive failure (
factor=2.0) until reaching the maximum threshold. - The
reset()method restores initial state upon successful requests, whileshould_notify()ensures users receive only one alert per outage cycle. - Integration in
task/buy.pyandtask/buy_helpers.pyprevents application crashes during complete proxy pool failures while respecting rate limits.
Frequently Asked Questions
What happens when all proxies fail simultaneously in biliTickerBuy?
The application enters a backoff loop where it waits for exponentially increasing intervals (starting at 30 seconds, capped at 600 seconds) and displays a single warning notification. It continues retrying until a proxy becomes available again rather than terminating the session.
How does the proxy backoff algorithm calculate retry delays?
The algorithm uses the formula base_seconds * (factor ^ exhausted_rounds), rounded to the nearest integer. With default values, this produces delays of 30s, 60s, 120s, 240s, etc., until hitting the max_seconds ceiling defined in interface/config.py.
Can I customize the maximum wait time for proxy retries?
Yes, the max_seconds parameter is configurable when creating a ProxyBackoff instance. The default value of 600 seconds can be overridden in the constructor or adjusted in the application configuration to match your proxy pool's expected recovery time.
Where does the proxy backoff reset occur after failures?
The reset happens in task/buy_helpers.py immediately after a successful request completes. Calling proxy_backoff.reset() clears the exhausted_rounds counter and the notification flag, allowing the next failure sequence to start fresh from the base delay.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →