This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
import time
|
||||
from datetime import timedelta
|
||||
from pathlib import Path
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.db import transaction
|
||||
from django.utils import timezone
|
||||
|
||||
from finance.models import FormulaExport
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Remove expired formula workbooks and stale temporary files"
|
||||
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument("--loop", action="store_true")
|
||||
parser.add_argument("--interval", type=int, default=3600)
|
||||
|
||||
def handle(self, *args, **options):
|
||||
while True:
|
||||
jobs, files = self.clean_expired()
|
||||
self.stdout.write(f"Expired {jobs} jobs; removed {files} files")
|
||||
if not options["loop"]:
|
||||
return
|
||||
time.sleep(max(60, options["interval"]))
|
||||
|
||||
def clean_expired(self):
|
||||
export_root = Path(settings.MEDIA_ROOT) / "formula-exports"
|
||||
if export_root.is_symlink():
|
||||
raise ValueError("公式导出目录不能是符号链接")
|
||||
root = export_root.resolve()
|
||||
now = timezone.now()
|
||||
jobs = files = 0
|
||||
|
||||
for job in FormulaExport.objects.filter(status="succeeded", expires_at__lte=now).iterator():
|
||||
path = Path(job.path) if job.path else None
|
||||
resolved = path.resolve() if path and path.is_absolute() and not path.is_symlink() else None
|
||||
in_root = bool(resolved and resolved.is_relative_to(root))
|
||||
try:
|
||||
with transaction.atomic():
|
||||
if in_root and resolved.is_file():
|
||||
resolved.unlink()
|
||||
files += 1
|
||||
job.status, job.path = "expired", ""
|
||||
job.save(update_fields=["status", "path"])
|
||||
jobs += 1
|
||||
except OSError as exc:
|
||||
self.stderr.write(f"Could not remove expired export {job.pk}: {exc}")
|
||||
|
||||
cutoff = (now - timedelta(hours=24)).timestamp()
|
||||
if root.is_dir() and not root.is_symlink():
|
||||
for user_dir in root.iterdir():
|
||||
if user_dir.is_symlink() or not user_dir.is_dir():
|
||||
continue
|
||||
for path in user_dir.glob("*.tmp"):
|
||||
try:
|
||||
if path.is_symlink() or not path.is_file() or path.stat().st_mtime > cutoff:
|
||||
continue
|
||||
path.unlink()
|
||||
files += 1
|
||||
except OSError as exc:
|
||||
self.stderr.write(f"Could not remove stale temporary export {path.name}: {exc}")
|
||||
|
||||
return jobs, files
|
||||
Reference in New Issue
Block a user