fix finance balance delta recharges
This commit is contained in:
@@ -16,7 +16,7 @@ from app.models.upstream import Upstream
|
||||
from app.models.snapshot import UpstreamRateSnapshot
|
||||
from app.services.auth_config import normalize_auth_config
|
||||
from app.services.upstream_client import UpstreamClient, build_snapshot
|
||||
from app.services.snapshot_service import diff_snapshots, prune_snapshots
|
||||
from app.services.snapshot_service import diff_snapshots, prune_snapshots, write_balance_snapshot
|
||||
from app.services import webhook_service
|
||||
from app.services import website_sync
|
||||
from app.config import get_settings
|
||||
@@ -102,6 +102,7 @@ def _check_upstream(upstream_id: int) -> None:
|
||||
if balance is not None:
|
||||
upstream.balance = balance
|
||||
upstream.balance_updated_at = datetime.now(timezone.utc)
|
||||
write_balance_snapshot(db, upstream.id, balance)
|
||||
# ── 余额告警阈值检查 ──
|
||||
threshold = upstream.balance_alert_threshold
|
||||
if threshold is not None and threshold > 0:
|
||||
@@ -376,6 +377,16 @@ def start_scheduler() -> None:
|
||||
max_instances=1,
|
||||
misfire_grace_time=3600,
|
||||
)
|
||||
# Daily balance snapshot capture at 23:59 Asia/Shanghai
|
||||
_scheduler.add_job(
|
||||
_capture_balance_snapshots,
|
||||
trigger=CronTrigger(timezone="Asia/Shanghai", hour=23, minute=59),
|
||||
id="balance_snapshot_daily",
|
||||
replace_existing=True,
|
||||
coalesce=True,
|
||||
max_instances=1,
|
||||
misfire_grace_time=600,
|
||||
)
|
||||
logger.info("scheduler started with %d upstream job(s)", len(upstreams))
|
||||
finally:
|
||||
db.close()
|
||||
@@ -416,6 +427,52 @@ def _compute_finance_daily_summary() -> None:
|
||||
db.close()
|
||||
|
||||
|
||||
def _capture_balance_snapshots() -> None:
|
||||
"""Fetch balance for all balance_delta-mode upstreams and write a snapshot.
|
||||
|
||||
Runs daily at 23:59 Asia/Shanghai to capture the end-of-day boundary balance.
|
||||
Only writes a snapshot if balance fetch succeeds. Does NOT update the
|
||||
upstream.balance field (that's the regular check's job).
|
||||
"""
|
||||
db = SessionLocal()
|
||||
try:
|
||||
upstreams = db.query(Upstream).filter(
|
||||
Upstream.enabled == True,
|
||||
Upstream.finance_cost_mode == "balance_delta",
|
||||
Upstream.balance_endpoint != "",
|
||||
Upstream.balance_response_path != "",
|
||||
).all()
|
||||
for u in upstreams:
|
||||
try:
|
||||
auth_config = json.loads(u.auth_config_json or "{}")
|
||||
with UpstreamClient(
|
||||
base_url=u.base_url,
|
||||
api_prefix=u.api_prefix,
|
||||
auth_type=u.auth_type,
|
||||
auth_config=auth_config,
|
||||
timeout=float(u.timeout_seconds),
|
||||
on_auth_config_update=lambda updated: _persist_auth_config_update(u, updated),
|
||||
target_id=u.id,
|
||||
target_name=u.name,
|
||||
) as client:
|
||||
client.ensure_authenticated()
|
||||
raw_balance = client.get_balance(u.balance_endpoint, u.balance_response_path)
|
||||
if raw_balance is not None:
|
||||
balance = raw_balance / (u.balance_divisor or 1.0)
|
||||
write_balance_snapshot(db, u.id, balance)
|
||||
db.commit()
|
||||
logger.info("balance boundary snapshot for upstream %s: %.4f", u.name, balance)
|
||||
else:
|
||||
logger.warning("balance boundary snapshot: upstream %s returned None", u.name)
|
||||
except Exception as exc:
|
||||
db.rollback()
|
||||
logger.warning("balance boundary snapshot failed for upstream %s: %s", u.name, exc)
|
||||
except Exception:
|
||||
logger.exception("failed to capture balance boundary snapshots")
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
def stop_scheduler() -> None:
|
||||
if _scheduler.running:
|
||||
_scheduler.shutdown(wait=True)
|
||||
|
||||
Reference in New Issue
Block a user