fix(space): avoid deleting Gradio cache and tmp_gradio paths still in UI
Browse files
app.py
CHANGED
|
@@ -141,10 +141,25 @@ MAX_SEED = np.iinfo(np.int32).max
|
|
| 141 |
# Session helpers
|
| 142 |
# ---------------------------------------------------------------------------
|
| 143 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 144 |
def ensure_session_dir(req: Optional[gr.Request]) -> Path:
|
| 145 |
session_id = getattr(req, "session_hash", None) or "shared"
|
| 146 |
d = CACHE_DIR / str(session_id)
|
| 147 |
d.mkdir(parents=True, exist_ok=True)
|
|
|
|
| 148 |
return d
|
| 149 |
|
| 150 |
|
|
@@ -159,8 +174,10 @@ def clear_session_dir(req: Optional[gr.Request]) -> str:
|
|
| 159 |
|
| 160 |
|
| 161 |
def end_session(req: gr.Request):
|
| 162 |
-
|
|
|
|
| 163 |
shutil.rmtree(d, ignore_errors=True)
|
|
|
|
| 164 |
|
| 165 |
|
| 166 |
def _session_dir_latest_mtime(path: Path) -> float:
|
|
@@ -183,12 +200,14 @@ def _session_dir_latest_mtime(path: Path) -> float:
|
|
| 183 |
|
| 184 |
|
| 185 |
def prune_tmp_gradio_sessions(max_age_s: int) -> int:
|
| 186 |
-
"""Delete CACHE_DIR/<session>
|
| 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:
|
|
@@ -196,10 +215,15 @@ def prune_tmp_gradio_sessions(max_age_s: int) -> int:
|
|
| 196 |
for p in entries:
|
| 197 |
if not p.is_dir():
|
| 198 |
continue
|
|
|
|
| 199 |
try:
|
| 200 |
-
|
|
|
|
|
|
|
|
|
|
| 201 |
continue
|
| 202 |
shutil.rmtree(p, ignore_errors=True)
|
|
|
|
| 203 |
removed += 1
|
| 204 |
except OSError:
|
| 205 |
continue
|
|
@@ -221,7 +245,7 @@ def start_tmp_gradio_pruner() -> None:
|
|
| 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(
|
| 225 |
|
| 226 |
def _loop() -> None:
|
| 227 |
while True:
|
|
@@ -848,7 +872,8 @@ def build_app() -> gr.Blocks:
|
|
| 848 |
),
|
| 849 |
title="NeAR",
|
| 850 |
css=CUSTOM_CSS,
|
| 851 |
-
|
|
|
|
| 852 |
fill_width=True,
|
| 853 |
) as demo:
|
| 854 |
asset_state = gr.State({})
|
|
|
|
| 141 |
# Session helpers
|
| 142 |
# ---------------------------------------------------------------------------
|
| 143 |
|
| 144 |
+
_SESSION_LAST_TOUCH: Dict[str, float] = {}
|
| 145 |
+
_SESSION_TOUCH_LOCK = threading.Lock()
|
| 146 |
+
|
| 147 |
+
|
| 148 |
+
def _session_touch(session_id: str) -> None:
|
| 149 |
+
with _SESSION_TOUCH_LOCK:
|
| 150 |
+
_SESSION_LAST_TOUCH[session_id] = time.time()
|
| 151 |
+
|
| 152 |
+
|
| 153 |
+
def _session_forget(session_id: str) -> None:
|
| 154 |
+
with _SESSION_TOUCH_LOCK:
|
| 155 |
+
_SESSION_LAST_TOUCH.pop(session_id, None)
|
| 156 |
+
|
| 157 |
+
|
| 158 |
def ensure_session_dir(req: Optional[gr.Request]) -> Path:
|
| 159 |
session_id = getattr(req, "session_hash", None) or "shared"
|
| 160 |
d = CACHE_DIR / str(session_id)
|
| 161 |
d.mkdir(parents=True, exist_ok=True)
|
| 162 |
+
_session_touch(session_id)
|
| 163 |
return d
|
| 164 |
|
| 165 |
|
|
|
|
| 174 |
|
| 175 |
|
| 176 |
def end_session(req: gr.Request):
|
| 177 |
+
session_id = getattr(req, "session_hash", None) or "shared"
|
| 178 |
+
d = CACHE_DIR / str(session_id)
|
| 179 |
shutil.rmtree(d, ignore_errors=True)
|
| 180 |
+
_session_forget(session_id)
|
| 181 |
|
| 182 |
|
| 183 |
def _session_dir_latest_mtime(path: Path) -> float:
|
|
|
|
| 200 |
|
| 201 |
|
| 202 |
def prune_tmp_gradio_sessions(max_age_s: int) -> int:
|
| 203 |
+
"""Delete CACHE_DIR/<session> when both API idle and on-disk files are older than max_age_s."""
|
| 204 |
|
| 205 |
if max_age_s <= 0 or not CACHE_DIR.is_dir():
|
| 206 |
return 0
|
| 207 |
now = time.time()
|
| 208 |
removed = 0
|
| 209 |
+
with _SESSION_TOUCH_LOCK:
|
| 210 |
+
touch_snap = dict(_SESSION_LAST_TOUCH)
|
| 211 |
try:
|
| 212 |
entries = list(CACHE_DIR.iterdir())
|
| 213 |
except OSError:
|
|
|
|
| 215 |
for p in entries:
|
| 216 |
if not p.is_dir():
|
| 217 |
continue
|
| 218 |
+
sid = p.name
|
| 219 |
try:
|
| 220 |
+
last_api = touch_snap.get(sid)
|
| 221 |
+
latest_file = _session_dir_latest_mtime(p)
|
| 222 |
+
last_seen = max(last_api or 0.0, latest_file)
|
| 223 |
+
if now - last_seen < max_age_s:
|
| 224 |
continue
|
| 225 |
shutil.rmtree(p, ignore_errors=True)
|
| 226 |
+
_session_forget(sid)
|
| 227 |
removed += 1
|
| 228 |
except OSError:
|
| 229 |
continue
|
|
|
|
| 245 |
if _tmp_pruner_started:
|
| 246 |
return
|
| 247 |
_tmp_pruner_started = True
|
| 248 |
+
max_age = int(os.environ.get("NEAR_TMP_GRADIO_MAX_AGE_S", str(48 * 3600)))
|
| 249 |
|
| 250 |
def _loop() -> None:
|
| 251 |
while True:
|
|
|
|
| 872 |
),
|
| 873 |
title="NeAR",
|
| 874 |
css=CUSTOM_CSS,
|
| 875 |
+
# (600, 600) deletes Gradio /tmp/gradio uploads in ~10m while the UI may still reference paths.
|
| 876 |
+
delete_cache=None,
|
| 877 |
fill_width=True,
|
| 878 |
) as demo:
|
| 879 |
asset_state = gr.State({})
|