Add cleanup functionality for older files and update environment configuration
- Introduced `IMGWK_CLEAN_OLDER_THAN_SEC` in the .env file to specify the age of files to be cleaned. - Enhanced `_safe_rmtree_contents` and `_cleanup_dir` functions to conditionally remove files older than the specified duration. - Updated worker status to include device provider information. - Modified tray application title to reflect the current provider status.
This commit is contained in:
parent
938c998cf3
commit
87f4551420
1
.env
1
.env
|
|
@ -20,3 +20,4 @@ IMGWK_REMBG_PROVIDER=auto # auto|dml|cpu
|
||||||
|
|
||||||
IMGWK_NO_TRAY = 0 # IMGWK_NO_TRAY=1 설정 시 트레이 비활성화
|
IMGWK_NO_TRAY = 0 # IMGWK_NO_TRAY=1 설정 시 트레이 비활성화
|
||||||
|
|
||||||
|
IMGWK_CLEAN_OLDER_THAN_SEC = 600 # 5분이 지난 파일만 정리하기
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
# 큐 대기 한도(가득 차면 429)
|
||||||
|
IMGWK_MAX_PENDING=400
|
||||||
|
|
||||||
|
IMGWK_WORKER_READY_TIMEOUT_SEC = 120 # 워커 작시 READY 타임아웃
|
||||||
|
|
||||||
|
# 워커 롤링 임계치
|
||||||
|
IMGWK_ROLL_MAX_RSS_MB=3600
|
||||||
|
IMGWK_ROLL_MAX_JOBS=500
|
||||||
|
IMGWK_ROLL_MAX_UPTIME_SEC=3600
|
||||||
|
|
||||||
|
# 잡 타임아웃(초)
|
||||||
|
IMGWK_JOB_TIMEOUT_SEC=600
|
||||||
|
|
||||||
|
# 테스트: 2건마다 워커 재시작 (1=활성화)
|
||||||
|
IMGWK_TEST_ROLL_EVERY_2=0
|
||||||
|
|
||||||
|
IMGWK_OCR_PROVIDER=auto # auto|dml|cpu
|
||||||
|
IMGWK_MIGAN_PROVIDER=auto # auto|dml|cpu
|
||||||
|
IMGWK_REMBG_PROVIDER=auto # auto|dml|cpu
|
||||||
|
|
||||||
|
IMGWK_NO_TRAY = 0 # IMGWK_NO_TRAY=1 설정 시 트레이 비활성화
|
||||||
|
|
||||||
|
IMGWK_CLEAN_OLDER_THAN_SEC = 600 # 5분이 지난 파일만 정리하기
|
||||||
Binary file not shown.
84
main.py
84
main.py
|
|
@ -238,7 +238,12 @@ def _cleanup_runtime_files():
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def _safe_rmtree_contents(target_dir: str):
|
def _safe_rmtree_contents(target_dir: str, older_than_sec: int = 0):
|
||||||
|
"""대상 디렉터리 하위의 항목을 삭제.
|
||||||
|
|
||||||
|
older_than_sec > 0 이면, 현재시각 기준 해당 초보다 오래된 항목만 삭제한다.
|
||||||
|
디렉터리는 내부 파일을 조건에 따라 정리한 뒤 비어 있으면 삭제한다.
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
if not target_dir:
|
if not target_dir:
|
||||||
return
|
return
|
||||||
|
|
@ -251,13 +256,51 @@ def _safe_rmtree_contents(target_dir: str):
|
||||||
except Exception:
|
except Exception:
|
||||||
return
|
return
|
||||||
os.makedirs(td, exist_ok=True)
|
os.makedirs(td, exist_ok=True)
|
||||||
|
|
||||||
|
now_ts = time.time()
|
||||||
|
threshold = max(0, int(older_than_sec or 0))
|
||||||
|
|
||||||
|
def _remove_file_if_old(fp: str):
|
||||||
|
try:
|
||||||
|
if threshold <= 0:
|
||||||
|
os.remove(fp)
|
||||||
|
return
|
||||||
|
mt = os.path.getmtime(fp)
|
||||||
|
if (now_ts - mt) >= threshold:
|
||||||
|
os.remove(fp)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _cleanup_dir(dp: str):
|
||||||
|
try:
|
||||||
|
# 파일은 조건부 삭제
|
||||||
|
for root, dirs, files in os.walk(dp, topdown=False):
|
||||||
|
for fn in files:
|
||||||
|
_remove_file_if_old(os.path.join(root, fn))
|
||||||
|
# 하위 폴더는 비어 있으면 삭제(항상 안전)
|
||||||
|
for dn in dirs:
|
||||||
|
full = os.path.join(root, dn)
|
||||||
|
try:
|
||||||
|
if not os.listdir(full):
|
||||||
|
os.rmdir(full)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
# 최상위 폴더도 비어 있으면 삭제
|
||||||
|
try:
|
||||||
|
if os.path.isdir(dp) and not os.listdir(dp):
|
||||||
|
os.rmdir(dp)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
for name in os.listdir(td):
|
for name in os.listdir(td):
|
||||||
p = os.path.join(td, name)
|
p = os.path.join(td, name)
|
||||||
try:
|
try:
|
||||||
if os.path.isdir(p):
|
if os.path.isdir(p):
|
||||||
shutil.rmtree(p, ignore_errors=True)
|
_cleanup_dir(p)
|
||||||
else:
|
else:
|
||||||
os.remove(p)
|
_remove_file_if_old(p)
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
except Exception:
|
except Exception:
|
||||||
|
|
@ -271,8 +314,12 @@ def _purge_temp_dirs():
|
||||||
work_dir = os.path.join(APP_DATA_DIR, "work")
|
work_dir = os.path.join(APP_DATA_DIR, "work")
|
||||||
output_dir = os.path.join(APP_DATA_DIR, "output")
|
output_dir = os.path.join(APP_DATA_DIR, "output")
|
||||||
outputs_dir = os.path.join(APP_DATA_DIR, "outputs")
|
outputs_dir = os.path.join(APP_DATA_DIR, "outputs")
|
||||||
|
try:
|
||||||
|
ttl = int(os.environ.get("IMGWK_CLEAN_OLDER_THAN_SEC", "300"))
|
||||||
|
except Exception:
|
||||||
|
ttl = 300
|
||||||
for d in (incoming_dir, work_dir, output_dir, outputs_dir):
|
for d in (incoming_dir, work_dir, output_dir, outputs_dir):
|
||||||
_safe_rmtree_contents(d)
|
_safe_rmtree_contents(d, older_than_sec=max(0, ttl))
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
@ -442,6 +489,8 @@ class WorkerManager:
|
||||||
# 실행 상태/성능 지표
|
# 실행 상태/성능 지표
|
||||||
self._running_jobs = 0
|
self._running_jobs = 0
|
||||||
self._recent_total_ms = [] # 최근 작업 total_ms 집계
|
self._recent_total_ms = [] # 최근 작업 total_ms 집계
|
||||||
|
# 최근 추론 장치(DML/GPU/CPU) 요약
|
||||||
|
self._last_device = None
|
||||||
|
|
||||||
# 기본 토글/설정(필요 시 요청에서 오버라이드)
|
# 기본 토글/설정(필요 시 요청에서 오버라이드)
|
||||||
self._toggle_states: Dict[str, Any] = {
|
self._toggle_states: Dict[str, Any] = {
|
||||||
|
|
@ -621,6 +670,17 @@ class WorkerManager:
|
||||||
self._recent_total_ms.append(total_ms)
|
self._recent_total_ms.append(total_ms)
|
||||||
if len(self._recent_total_ms) > 100:
|
if len(self._recent_total_ms) > 100:
|
||||||
self._recent_total_ms = self._recent_total_ms[-100:]
|
self._recent_total_ms = self._recent_total_ms[-100:]
|
||||||
|
# 최근 장치 정보 업데이트
|
||||||
|
try:
|
||||||
|
rr = job.result if isinstance(job.result, dict) else {}
|
||||||
|
dev = (rr.get("inpaint_device") or rr.get("device") or rr.get("provider") or "").lower()
|
||||||
|
if dev:
|
||||||
|
if ("dml" in dev) or ("directml" in dev) or ("gpu" in dev):
|
||||||
|
self._last_device = "dml"
|
||||||
|
elif "cpu" in dev:
|
||||||
|
self._last_device = "cpu"
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
except Exception:
|
except Exception:
|
||||||
|
|
@ -1079,12 +1139,23 @@ def worker_status():
|
||||||
ready = _worker.is_ready if _worker else False
|
ready = _worker.is_ready if _worker else False
|
||||||
avg_sec = None
|
avg_sec = None
|
||||||
active = False
|
active = False
|
||||||
|
provider = None
|
||||||
|
running_jobs = 0
|
||||||
|
pending_jobs = 0
|
||||||
try:
|
try:
|
||||||
if _worker is not None:
|
if _worker is not None:
|
||||||
active = bool(getattr(_worker, "_running_jobs", 0) > 0)
|
running_jobs = int(getattr(_worker, "_running_jobs", 0) or 0)
|
||||||
|
try:
|
||||||
|
pending_jobs = int(_worker.pending_jobs_count())
|
||||||
|
except Exception:
|
||||||
|
pending_jobs = 0
|
||||||
|
# 대기중이거나 실행중이면 ACTIVE
|
||||||
|
active = bool((running_jobs + pending_jobs) > 0)
|
||||||
arr = getattr(_worker, "_recent_total_ms", [])
|
arr = getattr(_worker, "_recent_total_ms", [])
|
||||||
if arr:
|
if arr:
|
||||||
avg_sec = (sum(arr) / len(arr)) / 1000.0
|
avg_sec = (sum(arr) / len(arr)) / 1000.0
|
||||||
|
# 최근 장치 표시(dml|cpu)
|
||||||
|
provider = getattr(_worker, "_last_device", None)
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
return {
|
return {
|
||||||
|
|
@ -1092,6 +1163,9 @@ def worker_status():
|
||||||
"pid": _worker.pid if _worker else None,
|
"pid": _worker.pid if _worker else None,
|
||||||
"active": active,
|
"active": active,
|
||||||
"avg_sec_per_image": avg_sec,
|
"avg_sec_per_image": avg_sec,
|
||||||
|
"provider": provider,
|
||||||
|
"running_jobs": running_jobs,
|
||||||
|
"pending_jobs": pending_jobs,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Binary file not shown.
Binary file not shown.
|
|
@ -114,7 +114,7 @@ def worker_main(
|
||||||
try:
|
try:
|
||||||
base_program = os.environ.get("PROGRAMDATA", r"C:\\ProgramData")
|
base_program = os.environ.get("PROGRAMDATA", r"C:\\ProgramData")
|
||||||
app_data_dir = os.path.join(base_program, "ImgWorker")
|
app_data_dir = os.path.join(base_program, "ImgWorker")
|
||||||
def _safe_rmtree_contents(target_dir: str):
|
def _safe_rmtree_contents(target_dir: str, older_than_sec: int = 300):
|
||||||
try:
|
try:
|
||||||
if not target_dir:
|
if not target_dir:
|
||||||
return
|
return
|
||||||
|
|
@ -123,20 +123,34 @@ def worker_main(
|
||||||
if os.path.commonpath([base, td]) != base:
|
if os.path.commonpath([base, td]) != base:
|
||||||
return
|
return
|
||||||
os.makedirs(td, exist_ok=True)
|
os.makedirs(td, exist_ok=True)
|
||||||
for name in os.listdir(td):
|
now_ts = time.time()
|
||||||
p = os.path.join(td, name)
|
thr = max(0, int(older_than_sec or 0))
|
||||||
|
|
||||||
|
def _remove_if_old(fp: str):
|
||||||
try:
|
try:
|
||||||
if os.path.isdir(p):
|
if thr <= 0:
|
||||||
import shutil as _sh
|
os.remove(fp)
|
||||||
_sh.rmtree(p, ignore_errors=True)
|
return
|
||||||
else:
|
mt = os.path.getmtime(fp)
|
||||||
os.remove(p)
|
if (now_ts - mt) >= thr:
|
||||||
|
os.remove(fp)
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
for root, dirs, files in os.walk(td, topdown=False):
|
||||||
|
for fn in files:
|
||||||
|
_remove_if_old(os.path.join(root, fn))
|
||||||
|
for dn in dirs:
|
||||||
|
full = os.path.join(root, dn)
|
||||||
|
try:
|
||||||
|
if not os.listdir(full):
|
||||||
|
os.rmdir(full)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
for d in (os.path.join(app_data_dir, "incoming"), os.path.join(app_data_dir, "work"), os.path.join(app_data_dir, "output"), os.path.join(app_data_dir, "outputs")):
|
for d in (os.path.join(app_data_dir, "incoming"), os.path.join(app_data_dir, "work"), os.path.join(app_data_dir, "output"), os.path.join(app_data_dir, "outputs")):
|
||||||
_safe_rmtree_contents(d)
|
_safe_rmtree_contents(d, older_than_sec=int(os.environ.get("IMGWK_CLEAN_OLDER_THAN_SEC", "300")))
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
@ -290,20 +304,37 @@ def worker_main(
|
||||||
if task is None:
|
if task is None:
|
||||||
logger.info("Shutdown signal 수신 → 종료")
|
logger.info("Shutdown signal 수신 → 종료")
|
||||||
try:
|
try:
|
||||||
# 종료 시 임시 폴더 정리
|
# 종료 시 임시 폴더 정리(5분 경과 파일만)
|
||||||
base_program = os.environ.get("PROGRAMDATA", r"C:\\ProgramData")
|
base_program = os.environ.get("PROGRAMDATA", r"C:\\ProgramData")
|
||||||
app_data_dir = os.path.join(base_program, "ImgWorker")
|
app_data_dir = os.path.join(base_program, "ImgWorker")
|
||||||
for d in (os.path.join(app_data_dir, "incoming"), os.path.join(app_data_dir, "work"), os.path.join(app_data_dir, "output"), os.path.join(app_data_dir, "outputs")):
|
def _cleanup_dir(dp: str, older_than_sec: int = 300):
|
||||||
try:
|
try:
|
||||||
for n in os.listdir(d):
|
now_ts = time.time()
|
||||||
p = os.path.join(d, n)
|
thr = max(0, int(older_than_sec or 0))
|
||||||
if os.path.isdir(p):
|
for root, dirs, files in os.walk(dp, topdown=False):
|
||||||
import shutil as _sh
|
for fn in files:
|
||||||
_sh.rmtree(p, ignore_errors=True)
|
fp = os.path.join(root, fn)
|
||||||
else:
|
try:
|
||||||
os.remove(p)
|
if thr <= 0:
|
||||||
|
os.remove(fp)
|
||||||
|
else:
|
||||||
|
mt = os.path.getmtime(fp)
|
||||||
|
if (now_ts - mt) >= thr:
|
||||||
|
os.remove(fp)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
for dn in dirs:
|
||||||
|
full = os.path.join(root, dn)
|
||||||
|
try:
|
||||||
|
if not os.listdir(full):
|
||||||
|
os.rmdir(full)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
ttl = int(os.environ.get("IMGWK_CLEAN_OLDER_THAN_SEC", "300"))
|
||||||
|
for d in (os.path.join(app_data_dir, "incoming"), os.path.join(app_data_dir, "work"), os.path.join(app_data_dir, "output"), os.path.join(app_data_dir, "outputs")):
|
||||||
|
_cleanup_dir(d, older_than_sec=ttl)
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
break
|
break
|
||||||
|
|
|
||||||
|
|
@ -49,11 +49,13 @@ class TrayController:
|
||||||
ready = bool(st.get("ready", False))
|
ready = bool(st.get("ready", False))
|
||||||
active = bool(st.get("active", False))
|
active = bool(st.get("active", False))
|
||||||
avg_sec = st.get("avg_sec_per_image")
|
avg_sec = st.get("avg_sec_per_image")
|
||||||
|
provider = (st.get("provider") or "").upper()
|
||||||
pid = st.get("pid")
|
pid = st.get("pid")
|
||||||
self._last_ready = ready
|
self._last_ready = ready
|
||||||
status_label = 'ACTIVE' if active else ('READY' if ready else 'STOP')
|
status_label = 'ACTIVE' if active else ('READY' if ready else 'STOP')
|
||||||
perf = f" - avg. {avg_sec:.1f}(sec/장)" if isinstance(avg_sec, (int, float)) else ''
|
perf = f" - avg. {avg_sec:.1f}(sec/장)" if isinstance(avg_sec, (int, float)) else ''
|
||||||
title = f"ImgWorker [{status_label}]{perf}"
|
prov = f" [{provider}]" if provider else ''
|
||||||
|
title = f"ImgWorker [{status_label}]{perf}{prov}"
|
||||||
if self.icon:
|
if self.icon:
|
||||||
self.icon.title = title
|
self.icon.title = title
|
||||||
# 메뉴를 상태에 맞게 재구성
|
# 메뉴를 상태에 맞게 재구성
|
||||||
|
|
|
||||||
13
setup.py
13
setup.py
|
|
@ -148,14 +148,11 @@ class BuildWithBytecode(_build_exe):
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# 추가 파일들: README, .env(있다면), 스크립트
|
# 추가 파일들: .env가 있으면 실행 파일과 같은 폴더에 포함
|
||||||
# EXTRA_FILES = [
|
ENV_FILE = os.path.join(ROOT_DIR, ".env")
|
||||||
# (os.path.join(ROOT_DIR, "README.md"), "README.md"),
|
if os.path.isfile(ENV_FILE):
|
||||||
# (os.path.join(ROOT_DIR, "requirements.txt"), "requirements.txt"),
|
# exe가 위치한 루트에 배치 → main.py의 load_dotenv(ROOT_DIR/.env)와 일치
|
||||||
# ]
|
DATA_FILES.append((ENV_FILE, ".env"))
|
||||||
# for src, dst in list(EXTRA_FILES):
|
|
||||||
# if os.path.isfile(src):
|
|
||||||
# DATA_FILES.append((src, dst))
|
|
||||||
|
|
||||||
# PowerShell 스크립트 포함
|
# PowerShell 스크립트 포함
|
||||||
# 배포 편의를 위해 modules/scripts 경로 사용
|
# 배포 편의를 위해 modules/scripts 경로 사용
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue