's'
This commit is contained in:
@@ -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",
|
||||
]
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user