Spaces:
Running
Running
Upload 2 files
Browse files- router_items.py +2 -2
- 数据库连接.py +37 -2
router_items.py
CHANGED
|
@@ -341,7 +341,7 @@ async def create_item(item: ItemCreate):
|
|
| 341 |
"rated_by": {}
|
| 342 |
}
|
| 343 |
items_db.insert(0, new_item)
|
| 344 |
-
db.save_data("items.json", items_db)
|
| 345 |
# 🗂️ 清除排序缓存
|
| 346 |
sort_cache.invalidate("items:")
|
| 347 |
|
|
@@ -446,7 +446,7 @@ async def update_item(item_id: str, update_data: ItemUpdate, current_user: str =
|
|
| 446 |
result_holder["error"] = "not_found"
|
| 447 |
return False
|
| 448 |
|
| 449 |
-
db.atomic_update("items.json", updater, default_data=[])
|
| 450 |
|
| 451 |
if result_holder.get("error") == "forbidden":
|
| 452 |
raise HTTPException(status_code=403, detail="无权修改他人发布的内容")
|
|
|
|
| 341 |
"rated_by": {}
|
| 342 |
}
|
| 343 |
items_db.insert(0, new_item)
|
| 344 |
+
db.save_data("items.json", items_db, force_sync=bool(item.github_token))
|
| 345 |
# 🗂️ 清除排序缓存
|
| 346 |
sort_cache.invalidate("items:")
|
| 347 |
|
|
|
|
| 446 |
result_holder["error"] = "not_found"
|
| 447 |
return False
|
| 448 |
|
| 449 |
+
db.atomic_update("items.json", updater, default_data=[], force_sync=bool(update_data.github_token))
|
| 450 |
|
| 451 |
if result_holder.get("error") == "forbidden":
|
| 452 |
raise HTTPException(status_code=403, detail="无权修改他人发布的内容")
|
数据库连接.py
CHANGED
|
@@ -357,13 +357,14 @@ def _recover_from_backup(file_name: str, default_data: Union[Dict, List]) -> Uni
|
|
| 357 |
# 4. 🚀 P1优化:保存后更新内存缓存
|
| 358 |
# 5. 异步同步到 HuggingFace
|
| 359 |
|
| 360 |
-
def save_data(file_name: str, data: Union[Dict, List]) -> bool:
|
| 361 |
"""
|
| 362 |
安全保存数据到 JSON 文件
|
| 363 |
|
| 364 |
参数:
|
| 365 |
file_name: 文件名(如 users.json)
|
| 366 |
data: 要保存的数据(dict 或 list)
|
|
|
|
| 367 |
|
| 368 |
返回:
|
| 369 |
True 保存成功 / False 保存失败
|
|
@@ -429,12 +430,42 @@ def save_data(file_name: str, data: Union[Dict, List]) -> bool:
|
|
| 429 |
# ========== 第五步:标记文件脏,等待批量同步 ==========
|
| 430 |
if HF_TOKEN:
|
| 431 |
_mark_dirty(file_name)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 432 |
|
| 433 |
|
| 434 |
# ==========================================
|
| 435 |
# ☁️ HF 批量同步机制
|
| 436 |
# ==========================================
|
| 437 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 438 |
def _mark_dirty(file_name: str):
|
| 439 |
"""标记文件为脏,等待下次批量同步"""
|
| 440 |
with _dirty_files_lock:
|
|
@@ -602,7 +633,7 @@ def get_backup_files() -> list:
|
|
| 602 |
# 🔒 原子更新函数(解决并发安全问题)
|
| 603 |
# ==========================================
|
| 604 |
|
| 605 |
-
def atomic_update(file_name: str, updater, default_data=None):
|
| 606 |
"""
|
| 607 |
原子性地读取、修改、保存 JSON 数据文件。
|
| 608 |
|
|
@@ -730,5 +761,9 @@ def atomic_update(file_name: str, updater, default_data=None):
|
|
| 730 |
# ========== 第五步:标记文件脏,等待批量同步 ==========
|
| 731 |
if HF_TOKEN:
|
| 732 |
_mark_dirty(file_name)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 733 |
|
| 734 |
return result
|
|
|
|
| 357 |
# 4. 🚀 P1优化:保存后更新内存缓存
|
| 358 |
# 5. 异步同步到 HuggingFace
|
| 359 |
|
| 360 |
+
def save_data(file_name: str, data: Union[Dict, List], force_sync: bool = False) -> bool:
|
| 361 |
"""
|
| 362 |
安全保存数据到 JSON 文件
|
| 363 |
|
| 364 |
参数:
|
| 365 |
file_name: 文件名(如 users.json)
|
| 366 |
data: 要保存的数据(dict 或 list)
|
| 367 |
+
force_sync: 是否立即同步到 HF Dataset(默认 False,等待30秒批量窗口)
|
| 368 |
|
| 369 |
返回:
|
| 370 |
True 保存成功 / False 保存失败
|
|
|
|
| 430 |
# ========== 第五步:标记文件脏,等待批量同步 ==========
|
| 431 |
if HF_TOKEN:
|
| 432 |
_mark_dirty(file_name)
|
| 433 |
+
|
| 434 |
+
# ⚡ force_sync=True 时立即同步到 HF Dataset(不等待批量窗口)
|
| 435 |
+
if force_sync:
|
| 436 |
+
_immediate_sync_file(file_name)
|
| 437 |
|
| 438 |
|
| 439 |
# ==========================================
|
| 440 |
# ☁️ HF 批量同步机制
|
| 441 |
# ==========================================
|
| 442 |
|
| 443 |
+
def _immediate_sync_file(file_name: str):
|
| 444 |
+
"""立即同步单个文件到 HF Dataset(后台线程,不阻塞请求)"""
|
| 445 |
+
def _do_sync():
|
| 446 |
+
try:
|
| 447 |
+
local_path = os.path.join(LOCAL_DB_DIR, file_name)
|
| 448 |
+
if not os.path.exists(local_path):
|
| 449 |
+
return
|
| 450 |
+
hf_api = HfApi(token=HF_TOKEN)
|
| 451 |
+
hf_api.upload_file(
|
| 452 |
+
path_or_fileobj=local_path,
|
| 453 |
+
path_in_repo=file_name,
|
| 454 |
+
repo_id=DATASET_REPO_ID,
|
| 455 |
+
repo_type="dataset",
|
| 456 |
+
commit_message=f"force sync: {file_name}"
|
| 457 |
+
)
|
| 458 |
+
logger.info(f"⚡ 即时同步成功: {file_name}")
|
| 459 |
+
# 同步成功后从脏文件集合中移除,避免批量同步重复上传
|
| 460 |
+
with _dirty_files_lock:
|
| 461 |
+
_dirty_files.discard(file_name)
|
| 462 |
+
except Exception as e:
|
| 463 |
+
logger.warning(f"⚡ 即时同步失败(将退回批量同步): {file_name} - {e}")
|
| 464 |
+
|
| 465 |
+
thread = threading.Thread(target=_do_sync, daemon=True)
|
| 466 |
+
thread.start()
|
| 467 |
+
|
| 468 |
+
|
| 469 |
def _mark_dirty(file_name: str):
|
| 470 |
"""标记文件为脏,等待下次批量同步"""
|
| 471 |
with _dirty_files_lock:
|
|
|
|
| 633 |
# 🔒 原子更新函数(解决并发安全问题)
|
| 634 |
# ==========================================
|
| 635 |
|
| 636 |
+
def atomic_update(file_name: str, updater, default_data=None, force_sync: bool = False):
|
| 637 |
"""
|
| 638 |
原子性地读取、修改、保存 JSON 数据文件。
|
| 639 |
|
|
|
|
| 761 |
# ========== 第五步:标记文件脏,等待批量同步 ==========
|
| 762 |
if HF_TOKEN:
|
| 763 |
_mark_dirty(file_name)
|
| 764 |
+
|
| 765 |
+
# ⚡ force_sync=True 时立即同步到 HF Dataset(不等待批量窗口)
|
| 766 |
+
if force_sync:
|
| 767 |
+
_immediate_sync_file(file_name)
|
| 768 |
|
| 769 |
return result
|