feat: add weighted proxy selection based on recency
Replace uniform random.choice with random.choices weighted by last_ok recency. Proxies tested successfully more recently get higher selection probability (weight = 1/(1 + age/300)), decaying over ~5 minutes.
This commit is contained in:
@@ -72,6 +72,51 @@ class TestProxyPoolGet:
|
||||
assert result.host == "1.2.3.4"
|
||||
|
||||
|
||||
class TestProxyPoolWeight:
|
||||
"""Test weighted proxy selection."""
|
||||
|
||||
def test_recent_proxy_preferred(self):
|
||||
import asyncio
|
||||
from collections import Counter
|
||||
|
||||
cfg = ProxyPoolConfig(sources=[])
|
||||
pool = ProxyPool(cfg, [], timeout=10.0)
|
||||
|
||||
now = time.time()
|
||||
fresh = ChainHop(proto="socks5", host="10.0.0.1", port=1080)
|
||||
stale = ChainHop(proto="socks5", host="10.0.0.2", port=1080)
|
||||
pool._proxies["socks5://10.0.0.1:1080"] = ProxyEntry(
|
||||
hop=fresh, alive=True, last_ok=now,
|
||||
)
|
||||
pool._proxies["socks5://10.0.0.2:1080"] = ProxyEntry(
|
||||
hop=stale, alive=True, last_ok=now - 3600,
|
||||
)
|
||||
pool._rebuild_alive()
|
||||
|
||||
counts: Counter[str] = Counter()
|
||||
for _ in range(1000):
|
||||
hop = asyncio.run(pool.get())
|
||||
counts[hop.host] += 1
|
||||
|
||||
assert counts["10.0.0.1"] > counts["10.0.0.2"] * 3
|
||||
|
||||
def test_weight_values(self):
|
||||
hop = ChainHop(proto="socks5", host="1.2.3.4", port=1080)
|
||||
now = 1000.0
|
||||
|
||||
# just tested
|
||||
entry = ProxyEntry(hop=hop, last_ok=now)
|
||||
assert ProxyPool._weight(entry, now) == pytest.approx(1.0)
|
||||
|
||||
# 5 minutes ago
|
||||
entry.last_ok = now - 300
|
||||
assert ProxyPool._weight(entry, now) == pytest.approx(0.5)
|
||||
|
||||
# never tested
|
||||
entry.last_ok = 0
|
||||
assert ProxyPool._weight(entry, now) == pytest.approx(0.01)
|
||||
|
||||
|
||||
class TestProxyPoolFetchFile:
|
||||
"""Test file source parsing."""
|
||||
|
||||
|
||||
Reference in New Issue
Block a user