1717
1818"""清理过期的沙箱实例"""
1919
20- import threading
2120import uuid
2221from concurrent .futures import ThreadPoolExecutor , as_completed
2322from dataclasses import dataclass
2625from django .db import close_old_connections
2726from django .utils import timezone
2827
28+ from paas_wl .infras .resources .base .base import get_client_by_cluster_name
29+ from paas_wl .infras .resources .base .kube_client import CoreDynamicClient
2930from paasng .platform .agent_sandbox .constants import SandboxStatus
3031from paasng .platform .agent_sandbox .exceptions import SandboxError
3132from paasng .platform .agent_sandbox .models import Sandbox
@@ -50,6 +51,24 @@ class _DeleteResult:
5051 error : SandboxError | None = None
5152
5253
54+ def _stdout_log_line (message : str ) -> str :
55+ ts = timezone .localtime (timezone .now ()).strftime ("%Y-%m-%d %H:%M:%S" )
56+ return f"[{ ts } ] { message } "
57+
58+
59+ def _warmup_kube_discovery_cache (cluster_names : set [str ]) -> None :
60+ """
61+ 预热(初始化)kubernetes dynamic client 的 discovery 磁盘缓存。
62+ 避免并发初始化缓存时同时读写该文件。
63+ Ref: https://github.com/kubernetes-client/python/issues/2037
64+ """
65+ for target in sorted (cluster_names ):
66+ if not target :
67+ continue
68+ client = get_client_by_cluster_name (target )
69+ CoreDynamicClient (client )
70+
71+
5372def _delete_expired_sandbox (sandbox_uuid : uuid .UUID ) -> _DeleteResult :
5473 close_old_connections ()
5574 sandbox = Sandbox .objects .select_related ("application" ).get (uuid = sandbox_uuid )
@@ -99,31 +118,38 @@ def handle(self, dry_run, concurrency, *args, **options):
99118 return
100119
101120 sandbox_uuids = list (sandboxes .values_list ("uuid" , flat = True ))
121+ targets = set (sandboxes .values_list ("target" , flat = True ).distinct ())
102122 deleted_count = 0
103123 failed_count = 0
104- output_lock = threading .Lock ()
105124 workers = min (concurrency , len (sandbox_uuids ))
106125
126+ if targets :
127+ self .stdout .write (f"预热 { len (targets )} 个集群的 K8s discovery 缓存: { ', ' .join (sorted (targets ))} " )
128+ _warmup_kube_discovery_cache (targets )
129+
107130 self .stdout .write (f"并发数: { workers } " )
108131
109132 with ThreadPoolExecutor (max_workers = workers ) as executor :
110133 futures = [executor .submit (_delete_expired_sandbox , sbx_uuid ) for sbx_uuid in sandbox_uuids ]
111134 for future in as_completed (futures ):
112135 result = future .result ()
113- with output_lock :
114- if result . success :
115- deleted_count += 1
116- self . stdout . write (
136+ if result . success :
137+ deleted_count += 1
138+ self . stdout . write (
139+ _stdout_log_line (
117140 f"已删除 { deleted_count } /{ total } uuid={ result .sandbox .uuid } "
118141 f"name={ result .sandbox .name } app_code={ result .sandbox .application .code } "
119142 )
120- else :
121- failed_count += 1
122- self .stdout .write (
123- self .style .ERROR (
143+ )
144+ else :
145+ failed_count += 1
146+ self .stdout .write (
147+ self .style .ERROR (
148+ _stdout_log_line (
124149 f"删除失败 uuid={ result .sandbox .uuid } name={ result .sandbox .name } "
125150 f"app_code={ result .sandbox .application .code } : { result .error } "
126151 )
127152 )
153+ )
128154
129155 self .stdout .write (f"\n 清理完成: 删除 { deleted_count } 个, 失败 { failed_count } 个" )
0 commit comments