This commit is contained in:
eric
2026-03-16 20:08:32 -05:00
parent e9898ab372
commit dc0f1dd9ec
15 changed files with 273 additions and 1714 deletions

View File

@@ -5,7 +5,13 @@
"""
from .pb import get_pb_client
from .memos import create_memos_user
from .payment import handle_payment_success, parse_order_id, processed_orders
from .payment import (
handle_payment_success,
parse_order_id,
processed_orders,
try_add_processed_order,
remove_processed_order,
)
__all__ = [
"get_pb_client",
@@ -13,4 +19,6 @@ __all__ = [
"handle_payment_success",
"parse_order_id",
"processed_orders",
"try_add_processed_order",
"remove_processed_order",
]

View File

@@ -1,16 +1,43 @@
"""支付成功后的统一业务处理(基于 SDK"""
import logging
import threading
import time
import requests
from cachetools import TTLCache
from ..config import PB_URL, PB_ADMIN_EMAIL, PB_ADMIN_PASSWORD
from .pb import get_pb_client
from .memos import create_memos_user
# 已处理订单(防重复)
processed_orders: set[str] = set()
# 已处理订单(防重复)24h TTL最大 10000 条,避免内存泄漏
_processed_orders: TTLCache[str, bool] = TTLCache(maxsize=10000, ttl=86400)
_processed_orders_lock = threading.Lock()
# 兼容旧导入
processed_orders = _processed_orders
DEFAULT_PASSWORD = "12345678"
# Admin token 缓存5 分钟),与 meetup/salon 一致
_ADMIN_TOKEN_CACHE: tuple[str, float] | None = None
_ADMIN_TOKEN_CACHE_TTL = 300
def try_add_processed_order(order_id: str) -> bool:
"""原子性标记订单已处理。返回 True 表示首次处理False 表示已处理过(跳过)。"""
with _processed_orders_lock:
if order_id in _processed_orders:
return False
_processed_orders[order_id] = True
return True
def remove_processed_order(order_id: str) -> None:
"""处理失败时移除标记,允许支付方重试。"""
with _processed_orders_lock:
_processed_orders.pop(order_id, None)
def parse_order_id(order_id: str) -> tuple[str, str]:
"""从 order_id 解析 user_id 和 pay_type"""
@@ -74,7 +101,11 @@ def _create_user_by_email(email: str) -> str | None:
def _get_admin_token() -> tuple[str | None, str | None]:
"""获取 PocketBase 管理员 token"""
"""获取 PocketBase 管理员 token,带 5 分钟缓存"""
global _ADMIN_TOKEN_CACHE
now = time.time()
if _ADMIN_TOKEN_CACHE and _ADMIN_TOKEN_CACHE[1] > now:
return _ADMIN_TOKEN_CACHE[0], None
if not PB_ADMIN_EMAIL or not PB_ADMIN_PASSWORD:
return None, "未配置"
base = (PB_URL or "").rstrip("/")
@@ -86,7 +117,10 @@ def _get_admin_token() -> tuple[str | None, str | None]:
timeout=10,
)
if r.status_code == 200:
return r.json().get("token"), None
token = r.json().get("token")
if token:
_ADMIN_TOKEN_CACHE = (token, now + _ADMIN_TOKEN_CACHE_TTL)
return token, None
if r.status_code == 404:
continue
except Exception:
@@ -217,7 +251,7 @@ def handle_payment_success(
except Exception as e:
logging.warning(f"site_vip 写入失败(不影响主流程): {e}")
processed_orders.add(order_id)
# 由回调方在验签后、调用前通过 try_add_processed_order 原子性标记,此处不再 add
except Exception as e:
logging.error("PocketBase 操作失败 order_id=%s error=%s", order_id, e)
raise