| """Apply feedback to the runtime table columns (in-place, lock-free inner ops). |
| |
| The caller (AccountDirectory) is responsible for holding the state lock before |
| calling these functions. |
| |
| Strategy-split functions |
| ------------------------ |
| ``apply_success`` / ``apply_rate_limited`` are split into ``*_quota`` and |
| ``*_random`` variants. The caller picks exactly one based on the active |
| selector strategy. No runtime ``if`` inside the apply helpers themselves. |
| """ |
|
|
| from app.platform.runtime.clock import now_s |
| from ..shared.enums import ALL_MODE_IDS, StatusId |
| from .table import AccountRuntimeTable |
|
|
| |
| _SUCCESS_STEP = 0.12 |
| _AUTH_FACTOR = 0.55 |
| _FORBIDDEN_FACTOR = 0.25 |
| _RATE_LIMIT_FACTOR = 0.45 |
| _SERVER_ERROR_FACTOR = 0.75 |
| _MIN_HEALTH = 0.05 |
| _MAX_HEALTH = 1.0 |
|
|
|
|
| |
| |
| |
|
|
|
|
| def apply_success_quota(table: AccountRuntimeTable, idx: int, mode_id: int) -> None: |
| """Quota strategy: decrement per-mode quota and improve health.""" |
| quota_col = table._quota_col(mode_id) |
| quota_col[idx] = max(0, int(quota_col[idx]) - 1) |
| _bump_health(table, idx) |
|
|
|
|
| def apply_success_random(table: AccountRuntimeTable, idx: int) -> None: |
| """Random strategy: only improve health; quota columns are ignored.""" |
| _bump_health(table, idx) |
|
|
|
|
| |
| |
| |
|
|
|
|
| def apply_rate_limited_quota( |
| table: AccountRuntimeTable, idx: int, mode_id: int |
| ) -> None: |
| """Quota strategy: zero the mode quota and reduce health.""" |
| table._quota_col(mode_id)[idx] = 0 |
| _adjust_health(table, idx, _RATE_LIMIT_FACTOR) |
|
|
|
|
| def apply_rate_limited_random( |
| table: AccountRuntimeTable, idx: int, *, cooling_sec: int |
| ) -> None: |
| """Random strategy: set per-account cooldown timestamp; do not touch quota. |
| |
| The account stays in ``mode_available``; ``_random_select`` filters it out |
| until ``cooling_until_s_by_idx`` has elapsed. |
| """ |
| ts = now_s() + max(0, cooling_sec) |
| cooling_col = table.cooling_until_s_by_idx |
| cooling_col[idx] = max(int(cooling_col[idx]), ts) |
| _adjust_health(table, idx, _RATE_LIMIT_FACTOR) |
|
|
|
|
| |
| |
| |
|
|
|
|
| def apply_auth_failure(table: AccountRuntimeTable, idx: int) -> None: |
| """Reduce health on 401; caller may mark account expired.""" |
| _adjust_health(table, idx, _AUTH_FACTOR) |
|
|
|
|
| def apply_forbidden(table: AccountRuntimeTable, idx: int) -> None: |
| """Reduce health heavily on 403.""" |
| _adjust_health(table, idx, _FORBIDDEN_FACTOR) |
|
|
|
|
| def apply_server_error(table: AccountRuntimeTable, idx: int) -> None: |
| """Mildly reduce health on 5xx / transport errors.""" |
| _adjust_health(table, idx, _SERVER_ERROR_FACTOR) |
|
|
|
|
| def apply_status_change( |
| table: AccountRuntimeTable, idx: int, new_status_id: int |
| ) -> None: |
| """Update status column and refresh availability indexes.""" |
| pool_id = int(table.pool_by_idx[idx]) |
| old_status = int(table.status_by_idx[idx]) |
|
|
| if old_status == new_status_id: |
| return |
|
|
| table.status_by_idx[idx] = new_status_id |
|
|
| if new_status_id != int(StatusId.ACTIVE): |
| for mode_id in ALL_MODE_IDS: |
| bucket = table.mode_available.get((pool_id, mode_id)) |
| if bucket: |
| bucket.discard(idx) |
| else: |
| for mode_id in ALL_MODE_IDS: |
| if int(table._quota_col(mode_id)[idx]) > 0: |
| table.mode_available.setdefault((pool_id, mode_id), set()).add(idx) |
|
|
|
|
| def apply_quota_update( |
| table: AccountRuntimeTable, |
| idx: int, |
| mode_id: int, |
| remaining: int, |
| reset_s: int, |
| ) -> None: |
| """Update quota and reset timestamp from upstream API data. |
| |
| Used exclusively by the quota strategy (refresh service). The random |
| strategy never calls this. |
| """ |
| quota_col = table._quota_col(mode_id) |
| reset_col = table._reset_col(mode_id) |
| quota_col[idx] = max(0, min(remaining, 32767)) |
| reset_col[idx] = reset_s |
|
|
| pool_id = int(table.pool_by_idx[idx]) |
| if int(table.status_by_idx[idx]) == int(StatusId.ACTIVE): |
| bucket = table.mode_available.setdefault((pool_id, mode_id), set()) |
| if int(table._window_col(mode_id)[idx]) > 0: |
| bucket.add(idx) |
|
|
|
|
| def increment_inflight(table: AccountRuntimeTable, idx: int) -> None: |
| table.inflight_by_idx[idx] = min(int(table.inflight_by_idx[idx]) + 1, 65535) |
|
|
|
|
| def decrement_inflight(table: AccountRuntimeTable, idx: int) -> None: |
| table.inflight_by_idx[idx] = max(0, int(table.inflight_by_idx[idx]) - 1) |
|
|
|
|
| def update_last_use(table: AccountRuntimeTable, idx: int, now_s: int) -> None: |
| table.last_use_at_by_idx[idx] = now_s |
|
|
|
|
| def update_last_fail(table: AccountRuntimeTable, idx: int, now_s: int) -> None: |
| table.last_fail_at_by_idx[idx] = now_s |
| table.fail_count_by_idx[idx] = min(int(table.fail_count_by_idx[idx]) + 1, 65535) |
|
|
|
|
| |
| |
| |
|
|
|
|
| def _bump_health(table: AccountRuntimeTable, idx: int) -> None: |
| table.health_by_idx[idx] = min( |
| _MAX_HEALTH, float(table.health_by_idx[idx]) + _SUCCESS_STEP |
| ) |
|
|
|
|
| def _adjust_health(table: AccountRuntimeTable, idx: int, factor: float) -> None: |
| table.health_by_idx[idx] = max( |
| _MIN_HEALTH, float(table.health_by_idx[idx]) * factor |
| ) |
|
|
|
|
| __all__ = [ |
| "apply_success_quota", |
| "apply_success_random", |
| "apply_rate_limited_quota", |
| "apply_rate_limited_random", |
| "apply_auth_failure", |
| "apply_forbidden", |
| "apply_server_error", |
| "apply_status_change", |
| "apply_quota_update", |
| "increment_inflight", |
| "decrement_inflight", |
| "update_last_use", |
| "update_last_fail", |
| ] |
|
|