fix: move HEAD request out of critical path — non-blocking background thread
The 10s HEAD request for Content-Length blocked the download endpoint response. nginx proxy in front (bench.srv2.sechpoint.app:443 → :5000) timed out waiting, returned empty response → 'data is null' JS error. Now wget starts immediately, response returns instantly, and HEAD runs in a daemon thread to populate content_length for ETA later.
This commit is contained in:
parent
c31ad3409a
commit
adfb68fe6b
1 changed files with 15 additions and 12 deletions
|
|
@ -20,6 +20,7 @@ from logging.handlers import RotatingFileHandler
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
|
import threading
|
||||||
import time
|
import time
|
||||||
import uuid
|
import uuid
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
@ -262,17 +263,7 @@ async def upload_raw(request: Request):
|
||||||
if free_gb < 50:
|
if free_gb < 50:
|
||||||
logger.warning("Low disk: %.1f GB free — download may fail", free_gb)
|
logger.warning("Low disk: %.1f GB free — download may fail", free_gb)
|
||||||
|
|
||||||
# Try to get file size via HEAD request (for speed estimation)
|
# Start wget immediately (HEAD request for size happens in background)
|
||||||
content_length = 0
|
|
||||||
try:
|
|
||||||
head_resp = http_requests.head(url, timeout=10, allow_redirects=True)
|
|
||||||
cl = head_resp.headers.get("Content-Length")
|
|
||||||
if cl:
|
|
||||||
content_length = int(cl)
|
|
||||||
logger.info("Download size from HEAD: %.1f GiB", content_length / (1024**3))
|
|
||||||
except Exception:
|
|
||||||
logger.info("Could not determine download size (HEAD failed — will skip ETA check)")
|
|
||||||
|
|
||||||
logger.info("Starting background download: %s → %s", url, dest)
|
logger.info("Starting background download: %s → %s", url, dest)
|
||||||
try:
|
try:
|
||||||
proc = subprocess.Popen(
|
proc = subprocess.Popen(
|
||||||
|
|
@ -288,10 +279,22 @@ async def upload_raw(request: Request):
|
||||||
"vmid": vmid,
|
"vmid": vmid,
|
||||||
"vm_name": vm_name,
|
"vm_name": vm_name,
|
||||||
"start_time": time.time(),
|
"start_time": time.time(),
|
||||||
"content_length": content_length,
|
"content_length": 0,
|
||||||
"_last_logged_bytes": 0,
|
"_last_logged_bytes": 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Fire-and-forget HEAD request to get file size for ETA (non-blocking)
|
||||||
|
def _fetch_content_length():
|
||||||
|
try:
|
||||||
|
head_resp = http_requests.head(url, timeout=5, allow_redirects=True)
|
||||||
|
cl = head_resp.headers.get("Content-Length")
|
||||||
|
if cl and filename in _active_downloads:
|
||||||
|
_active_downloads[filename]["content_length"] = int(cl)
|
||||||
|
logger.info("Download size from HEAD: %.1f GiB", int(cl) / (1024**3))
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
threading.Thread(target=_fetch_content_length, daemon=True).start()
|
||||||
|
|
||||||
return JSONResponse({
|
return JSONResponse({
|
||||||
"phase": "downloading",
|
"phase": "downloading",
|
||||||
"filename": filename,
|
"filename": filename,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue