feat: clean commit without .next
This commit is contained in:
@@ -115,6 +115,14 @@ def _check_base_url():
|
|||||||
@app.on_event("startup")
|
@app.on_event("startup")
|
||||||
async def startup_event():
|
async def startup_event():
|
||||||
_check_base_url()
|
_check_base_url()
|
||||||
|
# 预热 PocketBase 连接,减少首个业务请求冷启动延迟
|
||||||
|
try:
|
||||||
|
from .services.pb import get_pb_client
|
||||||
|
|
||||||
|
get_pb_client()
|
||||||
|
logging.info("PocketBase client warmup done")
|
||||||
|
except Exception as error:
|
||||||
|
logging.warning("PocketBase client warmup failed: %s", error)
|
||||||
|
|
||||||
|
|
||||||
@app.get("/health")
|
@app.get("/health")
|
||||||
|
|||||||
@@ -33,6 +33,27 @@ _http_session.mount("https://", HTTPAdapter(pool_connections=32, pool_maxsize=64
|
|||||||
_admin_token_cache_lock = threading.Lock()
|
_admin_token_cache_lock = threading.Lock()
|
||||||
_admin_token_cache_value: str | None = None
|
_admin_token_cache_value: str | None = None
|
||||||
_admin_token_cache_expire_at = 0.0
|
_admin_token_cache_expire_at = 0.0
|
||||||
|
_vip_cache_lock = threading.Lock()
|
||||||
|
_vip_check_cache: dict[str, tuple[float, dict]] = {}
|
||||||
|
_VIP_CACHE_TTL_SECONDS = 20
|
||||||
|
|
||||||
|
|
||||||
|
def _cache_get(key: str):
|
||||||
|
now = time.time()
|
||||||
|
with _vip_cache_lock:
|
||||||
|
item = _vip_check_cache.get(key)
|
||||||
|
if not item:
|
||||||
|
return None
|
||||||
|
expire_at, value = item
|
||||||
|
if expire_at < now:
|
||||||
|
_vip_check_cache.pop(key, None)
|
||||||
|
return None
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
def _cache_set(key: str, value: dict, ttl: int = _VIP_CACHE_TTL_SECONDS):
|
||||||
|
with _vip_cache_lock:
|
||||||
|
_vip_check_cache[key] = (time.time() + ttl, value)
|
||||||
|
|
||||||
|
|
||||||
def _record_get(obj, key: str, default=None):
|
def _record_get(obj, key: str, default=None):
|
||||||
@@ -302,6 +323,10 @@ async def nomadvip_check_vip(user_id: str = ""):
|
|||||||
logging.info("[payjsapi] check_vip user_id=%s", user_id or "(empty)")
|
logging.info("[payjsapi] check_vip user_id=%s", user_id or "(empty)")
|
||||||
if not user_id:
|
if not user_id:
|
||||||
return {"vip": False, "error": "missing user_id"}
|
return {"vip": False, "error": "missing user_id"}
|
||||||
|
cache_key = f"check_vip:{user_id}"
|
||||||
|
cached = _cache_get(cache_key)
|
||||||
|
if cached is not None:
|
||||||
|
return cached
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from ..services.pb import get_pb_client
|
from ..services.pb import get_pb_client
|
||||||
@@ -309,7 +334,9 @@ async def nomadvip_check_vip(user_id: str = ""):
|
|||||||
pb = get_pb_client()
|
pb = get_pb_client()
|
||||||
if not _uid_has_vip(pb, user_id):
|
if not _uid_has_vip(pb, user_id):
|
||||||
logging.info("[payjsapi] check_vip miss user_id=%s vip=False", user_id)
|
logging.info("[payjsapi] check_vip miss user_id=%s vip=False", user_id)
|
||||||
return {"vip": False}
|
result = {"vip": False}
|
||||||
|
_cache_set(cache_key, result)
|
||||||
|
return result
|
||||||
|
|
||||||
email = _get_linked_email_for_user(pb, user_id)
|
email = _get_linked_email_for_user(pb, user_id)
|
||||||
if not email:
|
if not email:
|
||||||
@@ -326,10 +353,14 @@ async def nomadvip_check_vip(user_id: str = ""):
|
|||||||
user_id,
|
user_id,
|
||||||
email or "(none)",
|
email or "(none)",
|
||||||
)
|
)
|
||||||
return {"vip": True, "email": email}
|
result = {"vip": True, "email": email}
|
||||||
|
_cache_set(cache_key, result)
|
||||||
|
return result
|
||||||
except Exception as error:
|
except Exception as error:
|
||||||
logging.warning("[payjsapi] check_vip failed: %s", error)
|
logging.warning("[payjsapi] check_vip failed: %s", error)
|
||||||
return {"vip": False, "error": str(error)}
|
result = {"vip": False, "error": str(error)}
|
||||||
|
_cache_set(cache_key, result, ttl=5)
|
||||||
|
return result
|
||||||
|
|
||||||
def _get_pb_admin_token() -> str | None:
|
def _get_pb_admin_token() -> str | None:
|
||||||
"""获取 PocketBase 管理员 token。"""
|
"""获取 PocketBase 管理员 token。"""
|
||||||
@@ -671,6 +702,10 @@ async def nomadvip_check_vip_by_email(item: dict):
|
|||||||
|
|
||||||
if not email or not password:
|
if not email or not password:
|
||||||
return {"vip": False, "error": "missing email or password"}
|
return {"vip": False, "error": "missing email or password"}
|
||||||
|
cache_key = f"check_vip_by_email:{email}:{anonymous_user_id}"
|
||||||
|
cached = _cache_get(cache_key)
|
||||||
|
if cached is not None:
|
||||||
|
return cached
|
||||||
|
|
||||||
base = (PB_URL or "").rstrip("/")
|
base = (PB_URL or "").rstrip("/")
|
||||||
login_res = _http_session.post(
|
login_res = _http_session.post(
|
||||||
@@ -768,10 +803,12 @@ async def nomadvip_check_vip_by_email(item: dict):
|
|||||||
|
|
||||||
if not matched_user_id:
|
if not matched_user_id:
|
||||||
logging.info("[payjsapi] check_vip_by_email no vip match for email=%s", email)
|
logging.info("[payjsapi] check_vip_by_email no vip match for email=%s", email)
|
||||||
return {
|
result = {
|
||||||
"vip": False,
|
"vip": False,
|
||||||
"error": "no linked vip record found; provide the paid user_id if this is a historical anonymous order",
|
"error": "no linked vip record found; provide the paid user_id if this is a historical anonymous order",
|
||||||
}
|
}
|
||||||
|
_cache_set(cache_key, result, ttl=5)
|
||||||
|
return result
|
||||||
|
|
||||||
if recovered_anonymous_user_id:
|
if recovered_anonymous_user_id:
|
||||||
_pb_ensure_site_vip(admin_token, recovered_anonymous_user_id, pb_user_id)
|
_pb_ensure_site_vip(admin_token, recovered_anonymous_user_id, pb_user_id)
|
||||||
@@ -791,16 +828,20 @@ async def nomadvip_check_vip_by_email(item: dict):
|
|||||||
pb_user_id,
|
pb_user_id,
|
||||||
recovered_anonymous_user_id or "(none)",
|
recovered_anonymous_user_id or "(none)",
|
||||||
)
|
)
|
||||||
return {
|
result = {
|
||||||
"vip": True,
|
"vip": True,
|
||||||
"token": token,
|
"token": token,
|
||||||
"record": record,
|
"record": record,
|
||||||
"effectiveUserId": pb_user_id,
|
"effectiveUserId": pb_user_id,
|
||||||
"anonymousUserId": recovered_anonymous_user_id,
|
"anonymousUserId": recovered_anonymous_user_id,
|
||||||
}
|
}
|
||||||
|
_cache_set(cache_key, result)
|
||||||
|
return result
|
||||||
except Exception as error:
|
except Exception as error:
|
||||||
logging.warning("[payjsapi] check_vip_by_email failed: %s", error)
|
logging.warning("[payjsapi] check_vip_by_email failed: %s", error)
|
||||||
return {"vip": False, "error": str(error)}
|
result = {"vip": False, "error": str(error)}
|
||||||
|
_cache_set(cache_key, result, ttl=5)
|
||||||
|
return result
|
||||||
|
|
||||||
@router.get("/order_status")
|
@router.get("/order_status")
|
||||||
async def nomadvip_order_status(order_id: str = "", out_trade_no: str = ""):
|
async def nomadvip_order_status(order_id: str = "", out_trade_no: str = ""):
|
||||||
|
|||||||
Reference in New Issue
Block a user