Optimize S3 asset archive uploads

This commit is contained in:
chengkml
2026-06-15 19:04:50 +08:00
parent 3054b476ff
commit d23ac4f74c
2 changed files with 38 additions and 1 deletions
+5 -1
View File
@@ -286,6 +286,7 @@ def _write_archive_to_storage(
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Release ZIP 包不能为空")
driver.ensure_directory(storage_root_path)
ensured_directories = {normalize_virtual_path(storage_root_path)}
extracted_count = 0
try:
with zipfile.ZipFile(io.BytesIO(archive_content)) as archive:
@@ -296,7 +297,10 @@ def _write_archive_to_storage(
if relative_path is None:
continue
target_path = normalize_virtual_path(f"{storage_root_path.rstrip('/')}/{relative_path}")
driver.ensure_directory(_parent_virtual_path(target_path))
parent_path = _parent_virtual_path(target_path)
if parent_path not in ensured_directories:
driver.ensure_directory(parent_path)
ensured_directories.add(parent_path)
try:
content = archive.read(member)
except Exception as exc:
+33
View File
@@ -302,6 +302,7 @@ class S3StorageDriver:
def __init__(self, *, config: dict[str, Any], mount_root_path: str) -> None:
try:
import boto3
from botocore.config import Config
except ImportError as exc:
raise StorageNotConfiguredError("S3 driver requires boto3 dependency") from exc
@@ -309,6 +310,15 @@ class S3StorageDriver:
if not bucket:
raise StorageNotConfiguredError("S3 backend requires config.bucket")
client_config = Config(
connect_timeout=_coerce_positive_number(config.get("connect_timeout_seconds"), default=3.0),
read_timeout=_coerce_positive_number(config.get("read_timeout_seconds"), default=10.0),
retries={"max_attempts": int(_coerce_positive_number(config.get("max_attempts"), default=2.0))},
s3={"addressing_style": _coerce_non_empty_string(config.get("addressing_style")) or "path"},
request_checksum_calculation="when_required",
response_checksum_validation="when_required",
)
session = boto3.session.Session(
aws_access_key_id=_coerce_non_empty_string(config.get("access_key_id")),
aws_secret_access_key=_coerce_non_empty_string(config.get("secret_access_key")),
@@ -319,9 +329,11 @@ class S3StorageDriver:
"s3",
endpoint_url=_coerce_non_empty_string(config.get("endpoint_url")),
region_name=_coerce_non_empty_string(config.get("region_name")),
config=client_config,
)
self._bucket = bucket
self._root_prefix = _normalize_s3_prefix(mount_root_path)
self._should_write_directory_markers = bool(config.get("write_directory_markers", False))
def list_dir(self, path: str) -> list[StorageObject]:
normalized = normalize_virtual_path(path)
@@ -402,6 +414,12 @@ class S3StorageDriver:
if normalized == "/":
return
# S3-compatible object stores do not require directory marker objects
# before nested keys are written. The marker PUT is optional and is
# expensive on high-file-count uploads.
if not self._should_write_directory_markers:
return
key = self._key_for_path(normalized)
if key and not key.endswith("/"):
key = f"{key}/"
@@ -711,6 +729,21 @@ def _coerce_non_empty_string(value: Any) -> str | None:
return stripped if stripped else None
def _coerce_positive_number(value: Any, *, default: float) -> float:
if isinstance(value, bool):
return default
if isinstance(value, (int, float)):
number = float(value)
elif isinstance(value, str):
try:
number = float(value.strip())
except ValueError:
return default
else:
return default
return number if number > 0 else default
def _is_s3_not_found(exc: Exception) -> bool:
response = getattr(exc, "response", None)
if not isinstance(response, dict):