Fix rotation failover: advance past unavailable providers instead of retrying one (v0.99.99)

The dispatch loop skipped a provider via is_rate_limited() (which includes the
manual dashboard flag) but did NOT add it to tried_models, so the next retry
re-selected the SAME highest-weight provider every time. A manually-flagged /
rate-limited top-weight member (e.g. claude_think in rotation lisa) thus consumed
all max_retries and returned 429, never failing over to a working member
(kilo-stefy).

- Use _provider_in_availability_cooldown() instead of is_rate_limited() so the
  manual flag (rotation-membership only) does not block dispatch, consistent with
  the scan.
- Mark the skipped model as tried so failover actually advances to the next
  provider.
- Guard the dispatch handler build in try/except too (same bad-cred 500 class).

rotation/lisa now returns 200 via kilo-stefy instead of 429/500.
Co-Authored-By: 's avatarClaude Opus 4.8 (1M context) <noreply@anthropic.com>
parent eb7b4b36
...@@ -55,7 +55,7 @@ from .auth.qwen import QwenOAuth2 ...@@ -55,7 +55,7 @@ from .auth.qwen import QwenOAuth2
from .handlers import RequestHandler, RotationHandler, AutoselectHandler from .handlers import RequestHandler, RotationHandler, AutoselectHandler
from .utils import count_messages_tokens, split_messages_into_chunks, get_max_request_tokens_for_model, get_max_completion_tokens_for_model from .utils import count_messages_tokens, split_messages_into_chunks, get_max_request_tokens_for_model, get_max_completion_tokens_for_model
__version__ = "0.99.98" __version__ = "0.99.99"
__all__ = [ __all__ = [
# Config # Config
"config", "config",
......
...@@ -3846,11 +3846,24 @@ class RotationHandler: ...@@ -3846,11 +3846,24 @@ class RotationHandler:
continue continue
logger.info(f"Getting provider handler for {provider_id}") logger.info(f"Getting provider handler for {provider_id}")
handler = get_provider_handler(provider_id, api_key, user_id=self.user_id) try:
handler = get_provider_handler(provider_id, api_key, user_id=self.user_id)
except Exception as e:
logger.warning(f"Provider {provider_id} handler build failed ({e}); failing over to next model")
tried_models.append(current_model)
continue
logger.info(f"Provider handler obtained: {handler.__class__.__name__}") logger.info(f"Provider handler obtained: {handler.__class__.__name__}")
if handler.is_rate_limited(): # Only a genuine auto-disable cooldown (failure threshold / usage limit)
logger.warning(f"Provider {provider_id} is rate limited, skipping to next model") # skips a provider here. The manual dashboard flag is rotation-membership
# only (honoured by enabled:false in the scan), so it must NOT block
# dispatch — otherwise the scan marks a manually-flagged provider available
# but dispatch skips it. Crucially, mark the skipped model as tried so
# failover advances to the next provider instead of re-selecting this same
# one every retry (which exhausted max_retries and returned 429).
if _provider_in_availability_cooldown(handler):
logger.warning(f"Provider {provider_id} is in an auto-disable cooldown, failing over to next model")
tried_models.append(current_model)
continue continue
# Check token rate limits for this model # Check token rate limits for this model
......
...@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" ...@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project] [project]
name = "aisbf" name = "aisbf"
version = "0.99.98" version = "0.99.99"
description = "AISBF - AI Service Broker Framework || AI Should Be Free - A modular proxy server for managing multiple AI provider integrations" description = "AISBF - AI Service Broker Framework || AI Should Be Free - A modular proxy server for managing multiple AI provider integrations"
readme = "README.md" readme = "README.md"
license = "GPL-3.0-or-later" license = "GPL-3.0-or-later"
......
...@@ -106,7 +106,7 @@ class InstallCommand(_install): ...@@ -106,7 +106,7 @@ class InstallCommand(_install):
setup( setup(
name="aisbf", name="aisbf",
version="0.99.98", version="0.99.99",
author="AISBF Contributors", author="AISBF Contributors",
author_email="stefy@nexlab.net", author_email="stefy@nexlab.net",
description="AISBF - AI Service Broker Framework || AI Should Be Free - A modular proxy server for managing multiple AI provider integrations", description="AISBF - AI Service Broker Framework || AI Should Be Free - A modular proxy server for managing multiple AI provider integrations",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment