sycommon-python-lib 0.2.7a30__py3-none-any.whl → 0.2.7a31__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -350,15 +350,11 @@ async def _load_one_server(
350
350
  pass
351
351
  return []
352
352
  except asyncio.CancelledError:
353
- # 单飞失败透传的哨兵(_discover_with_cache 失败时唤醒等待者用),按失败处理
354
- SYLogger.warning(
355
- f"[MCP] 服务器 '{config.name}' ({config.server_url}) 发现失败,跳过")
356
- if on_server_failure:
357
- try:
358
- await on_server_failure(config.id, "发现失败")
359
- except Exception:
360
- pass
361
- return []
353
+ # 外层取消(如会话重置 cancel 后台 _mcp_task)→ 必须向上传播,不能吞。
354
+ # 吞掉会让 load_mcp_tools_background 的 `except CancelledError: raise` 守卫失效、
355
+ # 任务被标记为正常完成而非已取消。单飞失败的哨兵是 RuntimeError(走下方 except Exception)
356
+ # 不会进这个分支,故这里只需 raise。
357
+ raise
362
358
  except Exception as e:
363
359
  SYLogger.warning(
364
360
  f"[MCP] 服务器 '{config.name}' ({config.server_url}) 连接失败,跳过: {e}")
@@ -24,9 +24,24 @@ from sycommon.logging.kafka_log import SYLogger
24
24
  # 日期快照功能预留,当前暂不启用
25
25
  _SNAPSHOT_ENABLED = False
26
26
 
27
- # restore_from_minio 的 MinIO 下载并发度(同时下载的文件数上限)。
28
- # 与 _sync_batch(sync→minio 方向)的 batch_size 对齐为 5,避免压垮 MinIO/网络。
29
- _RESTORE_CONCURRENCY = 5
27
+ # restore_from_minio 的 MinIO 下载并发度。
28
+ # 两层信号量:
29
+ # - 单用户层 _RESTORE_PER_USER:每个用户恢复时最多 5 路并发下载(单用户恢复够快);
30
+ # - 全局层 _RESTORE_GLOBAL_CAP:全进程最多 15 路下载,防 N 个用户同时恢复时
31
+ # N×5 路把默认线程池(≈min(32,cpu+4)=12)打满、挤占主请求路径的沙箱操作。
32
+ # 单用户独享 5 槽 + 全局封顶 15,兼顾「单用户快」与「多用户不互相压垮」。
33
+ _RESTORE_PER_USER = 5
34
+ _RESTORE_GLOBAL_CAP = 15
35
+ # 全局信号量惰性创建(绑定到首次调用时的 event loop;单 loop 部署下不变)。
36
+ _RESTORE_DOWNLOAD_SEM: "asyncio.Semaphore | None" = None
37
+
38
+
39
+ def _get_restore_download_sem() -> "asyncio.Semaphore":
40
+ """惰性创建全局下载信号量。"""
41
+ global _RESTORE_DOWNLOAD_SEM
42
+ if _RESTORE_DOWNLOAD_SEM is None:
43
+ _RESTORE_DOWNLOAD_SEM = asyncio.Semaphore(_RESTORE_GLOBAL_CAP)
44
+ return _RESTORE_DOWNLOAD_SEM
30
45
 
31
46
 
32
47
  class MinioSyncService(metaclass=SingletonMeta):
@@ -763,15 +778,18 @@ class MinioSyncService(metaclass=SingletonMeta):
763
778
 
764
779
  SYLogger.info(f"[MinIO] 需恢复 {len(to_restore)} 个文件到沙箱: user={user_id}")
765
780
 
766
- # 4. 并发恢复:MinIO 下载用全局 Semaphore(5) 限流并发,沙箱上传仍按批 batch_upload。
767
- # 旧实现是「批内串行下载 + 批间串行」,N 个文件 ≈ N 次串行 MinIO GET,27 个文件要数十秒。
768
- # 改为 Semaphore(5) 后下载并发,总耗时 ≈ ceil(N/5) 次串行往返,对齐 _sync_batch 的并发度。
781
+ # 4. 并发恢复:两层限流。
782
+ # - per_user_sem(每次 restore 新建,本用户独享 5 槽):单用户恢复够快;
783
+ # - global_sem(进程级 15 槽):多用户同时恢复时全局封顶,防 5 路下载
784
+ # 打满线程池、挤占主请求路径的沙箱操作。
785
+ # 下载协程先抢本用户 5 槽、再抢全局 15 槽,故实际并发 = min(本用户待下载, 全局剩余)。
769
786
  restored = 0
770
- download_sem = asyncio.Semaphore(_RESTORE_CONCURRENCY)
787
+ global_sem = _get_restore_download_sem()
788
+ per_user_sem = asyncio.Semaphore(_RESTORE_PER_USER)
771
789
 
772
790
  async def _download_one(rel_path: str):
773
791
  """下载单个 MinIO 对象到内存,返回 (沙箱绝对路径, 内容) 或 None。"""
774
- async with download_sem:
792
+ async with per_user_sem, global_sem:
775
793
  try:
776
794
  def _download_object(bucket, key):
777
795
  resp = self._client.get_object(bucket, key)
@@ -786,18 +804,18 @@ class MinioSyncService(metaclass=SingletonMeta):
786
804
  )
787
805
  return (f"/{rel_path}", content)
788
806
  except Exception as e:
789
- SYLogger.warning(f"[MinIO] 下载文件失败: {rel_path}, error={e}")
807
+ SYLogger.warning(f"[MinIO] 下载文件失败: {rel_path}, error: {e}")
790
808
  return None
791
809
 
792
- # 全量并发下载( Semaphore 限流),比按批串行快得多
810
+ # 全量并发下载(受两层 Semaphore 限流),比按批串行快得多
793
811
  download_results = await asyncio.gather(
794
812
  *[_download_one(rp) for rp in to_restore]
795
813
  )
796
814
  downloaded = [r for r in download_results if r is not None]
797
815
 
798
816
  # 上传仍走 batch_upload(服务端并发),按 5 个一批发(沙箱端点对超大批量可能限流)
799
- for i in range(0, len(downloaded), _RESTORE_CONCURRENCY):
800
- batch = downloaded[i:i + _RESTORE_CONCURRENCY]
817
+ for i in range(0, len(downloaded), _RESTORE_PER_USER):
818
+ batch = downloaded[i:i + _RESTORE_PER_USER]
801
819
  if not batch:
802
820
  continue
803
821
  try:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sycommon-python-lib
3
- Version: 0.2.7a30
3
+ Version: 0.2.7a31
4
4
  Summary: Add your description here
5
5
  Requires-Python: >=3.11
6
6
  Description-Content-Type: text/markdown
@@ -146,7 +146,7 @@ sycommon/agent/acp/ssh_init.py,sha256=5y1kIyNHpsh9ayx9RWO5gS0GOOn2GfZpU4fNrGuhOY
146
146
  sycommon/agent/acp/tool.py,sha256=yt6ohKL2y7wIZMNiLv-m5oCg5u1p5GAbqgjzQVt285Y,10975
147
147
  sycommon/agent/mcp/__init__.py,sha256=iKrdDhIrFsNIkqG_kgcwNe-nOiM6uVfolKv44LfQ-FQ,636
148
148
  sycommon/agent/mcp/models.py,sha256=zda4ho-UTYOJ5oPAZPZ-vxhfDRLghUCsMroHnA2A2QQ,1490
149
- sycommon/agent/mcp/tool_loader.py,sha256=B0dCaRKm2WGGsK6d9TIp4zmuun6QxPwXCVFY7drKEkA,17824
149
+ sycommon/agent/mcp/tool_loader.py,sha256=pwhZoSoZuQVYo6BgfdMoRHlGnRPDRxvOvxEgvUM5q7Q,17818
150
150
  sycommon/agent/middleware/sandbox_path_guard.py,sha256=K1SnxA8pDxkCSucOkranwUvC9_8rd3l_-TIR8gMMTK8,8102
151
151
  sycommon/agent/middleware/sensitive_guard.py,sha256=8e7qSAoak0MNB5fRLscQF0PVGZ07SKdwmGk590GubOI,22870
152
152
  sycommon/agent/middleware/sitecustomize.py,sha256=Bt7XFnWV_LJo89l858AGp5VUkXwefpLGmjkCtLe-CMw,4800
@@ -157,7 +157,7 @@ sycommon/agent/sandbox/__init__.py,sha256=jR7LlkD4J4Y6QYyRXQClkwmqDBCCPmycV_hQV9
157
157
  sycommon/agent/sandbox/consistent_hash.py,sha256=8Jgk-W4NAD2-u5_vKRVlPmql_e0Vy4aNORiXOuzvIrs,7277
158
158
  sycommon/agent/sandbox/file_ops.py,sha256=VTK7xduMMWLVTr9JViMnmPeh7s8Ojr8YwYA4ovMZZg0,37138
159
159
  sycommon/agent/sandbox/http_sandbox_backend.py,sha256=1Cj_JYdvwP3PFPa_4xFPnrGdt67Wp5iQdoziSzjeqoE,70481
160
- sycommon/agent/sandbox/minio_sync.py,sha256=c2TQmnawlpfTyEalSmcIRSK4DNkrZluq-9SjoySrf-M,34515
160
+ sycommon/agent/sandbox/minio_sync.py,sha256=zloxzaoNhEgoiz43NcBalHC_LMd74BoBpr5rN_UfmDA,35432
161
161
  sycommon/agent/sandbox/sandbox_pool.py,sha256=eMn8sLakCWf90l6ni2-333QM8oBdX1CflV-WzneFp_k,9133
162
162
  sycommon/agent/sandbox/sandbox_recovery.py,sha256=X-eDODx1tmGMh_iTngV6e1ppfDBHpTdkPreJusN5MHY,7358
163
163
  sycommon/agent/sandbox/session.py,sha256=TjzC3yFC-VaJ75UwCyL26QX4PRTGNNfQae1FKFuOsYI,2365
@@ -308,8 +308,8 @@ sycommon/tools/syemail.py,sha256=BDFhgf7WDOQeTcjxJEQdu0dQhnHFPO_p3eI0-Ni3LhQ,561
308
308
  sycommon/tools/timing.py,sha256=OiiE7P07lRoMzX9kzb8sZU9cDb0zNnqIlY5pWqHcnkY,2064
309
309
  sycommon/xxljob/__init__.py,sha256=7eoBlQxv-B39IfRSCY2bkqdGYs1QRe1umAWd88VMEEM,86
310
310
  sycommon/xxljob/xxljob_service.py,sha256=1yifwIBNGsCIxLnQjHKiBlbsigc_zvPH-dMTZcNxe-Q,7649
311
- sycommon_python_lib-0.2.7a30.dist-info/METADATA,sha256=A_VXT1ygWDo4Hkvwonq65az8FeY0k_8ik6hkReVPKWY,7962
312
- sycommon_python_lib-0.2.7a30.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
313
- sycommon_python_lib-0.2.7a30.dist-info/entry_points.txt,sha256=gsR4SssKxDWjRU8ggidzNcdMXDPRSKRS7UaGyNP84Qg,92
314
- sycommon_python_lib-0.2.7a30.dist-info/top_level.txt,sha256=RgphKrg7nJyZ7irJqbxFr-5H2LUYTvI7ivoWZH2hcD0,29
315
- sycommon_python_lib-0.2.7a30.dist-info/RECORD,,
311
+ sycommon_python_lib-0.2.7a31.dist-info/METADATA,sha256=Tk61Oi4TEDQ8Slxh92K3AJzTEiKvtdIfo61T9TU3k8A,7962
312
+ sycommon_python_lib-0.2.7a31.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
313
+ sycommon_python_lib-0.2.7a31.dist-info/entry_points.txt,sha256=gsR4SssKxDWjRU8ggidzNcdMXDPRSKRS7UaGyNP84Qg,92
314
+ sycommon_python_lib-0.2.7a31.dist-info/top_level.txt,sha256=RgphKrg7nJyZ7irJqbxFr-5H2LUYTvI7ivoWZH2hcD0,29
315
+ sycommon_python_lib-0.2.7a31.dist-info/RECORD,,