luh1124 commited on
Commit
2396b9c
·
1 Parent(s): fd95ca1

feat(space): background prune stale tmp_gradio session dirs by age

Browse files
Files changed (1) hide show
  1. app.py +75 -0
app.py CHANGED
@@ -34,6 +34,7 @@ print(
34
 
35
  import shutil
36
  import threading
 
37
  from pathlib import Path
38
  from typing import Any, Dict, Optional
39
 
@@ -162,6 +163,79 @@ def end_session(req: gr.Request):
162
  shutil.rmtree(d, ignore_errors=True)
163
 
164
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
165
  def get_file_path(file_obj: Any) -> Optional[str]:
166
  if file_obj is None:
167
  return None
@@ -1110,6 +1184,7 @@ def build_app() -> gr.Blocks:
1110
 
1111
  demo = build_app()
1112
  demo.queue(max_size=8)
 
1113
 
1114
  # ---------------------------------------------------------------------------
1115
  # Entry point
 
34
 
35
  import shutil
36
  import threading
37
+ import time
38
  from pathlib import Path
39
  from typing import Any, Dict, Optional
40
 
 
163
  shutil.rmtree(d, ignore_errors=True)
164
 
165
 
166
+ def _session_dir_latest_mtime(path: Path) -> float:
167
+ """Latest mtime among path and all nested files (best-effort for 'last activity')."""
168
+
169
+ try:
170
+ latest = path.stat().st_mtime
171
+ except OSError:
172
+ return 0.0
173
+ try:
174
+ for child in path.rglob("*"):
175
+ if child.is_file():
176
+ try:
177
+ latest = max(latest, child.stat().st_mtime)
178
+ except OSError:
179
+ pass
180
+ except OSError:
181
+ pass
182
+ return latest
183
+
184
+
185
+ def prune_tmp_gradio_sessions(max_age_s: int) -> int:
186
+ """Delete CACHE_DIR/<session> trees with no nested file activity for max_age_s. Returns removed count."""
187
+
188
+ if max_age_s <= 0 or not CACHE_DIR.is_dir():
189
+ return 0
190
+ now = time.time()
191
+ removed = 0
192
+ try:
193
+ entries = list(CACHE_DIR.iterdir())
194
+ except OSError:
195
+ return 0
196
+ for p in entries:
197
+ if not p.is_dir():
198
+ continue
199
+ try:
200
+ if now - _session_dir_latest_mtime(p) < max_age_s:
201
+ continue
202
+ shutil.rmtree(p, ignore_errors=True)
203
+ removed += 1
204
+ except OSError:
205
+ continue
206
+ return removed
207
+
208
+
209
+ _tmp_pruner_started = False
210
+ _tmp_pruner_lock = threading.Lock()
211
+
212
+
213
+ def start_tmp_gradio_pruner() -> None:
214
+ """Background prune of tmp_gradio session dirs (disk, not RAM). Configurable via env."""
215
+
216
+ global _tmp_pruner_started
217
+ interval = int(os.environ.get("NEAR_TMP_PRUNE_INTERVAL_S", "900"))
218
+ if interval <= 0:
219
+ return
220
+ with _tmp_pruner_lock:
221
+ if _tmp_pruner_started:
222
+ return
223
+ _tmp_pruner_started = True
224
+ max_age = int(os.environ.get("NEAR_TMP_GRADIO_MAX_AGE_S", str(6 * 3600)))
225
+
226
+ def _loop() -> None:
227
+ while True:
228
+ try:
229
+ n = prune_tmp_gradio_sessions(max_age)
230
+ if n:
231
+ print(f"[NeAR] tmp_gradio prune: removed {n} stale session dir(s)", flush=True)
232
+ except Exception as exc:
233
+ print(f"[NeAR] tmp_gradio prune error: {exc}", flush=True)
234
+ time.sleep(interval)
235
+
236
+ threading.Thread(target=_loop, daemon=True, name="near-tmp-prune").start()
237
+
238
+
239
  def get_file_path(file_obj: Any) -> Optional[str]:
240
  if file_obj is None:
241
  return None
 
1184
 
1185
  demo = build_app()
1186
  demo.queue(max_size=8)
1187
+ start_tmp_gradio_pruner()
1188
 
1189
  # ---------------------------------------------------------------------------
1190
  # Entry point