You've already forked FrameTour-RenderWorker
refactor
This commit is contained in:
@@ -1,6 +1,10 @@
|
||||
from .render_service import RenderService, DefaultRenderService
|
||||
from .task_service import TaskService, DefaultTaskService
|
||||
from .template_service import TemplateService, DefaultTemplateService
|
||||
from .service_container import (
|
||||
ServiceContainer, get_container, register_default_services,
|
||||
get_render_service, get_template_service, get_task_service
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
'RenderService',
|
||||
@@ -8,5 +12,11 @@ __all__ = [
|
||||
'TaskService',
|
||||
'DefaultTaskService',
|
||||
'TemplateService',
|
||||
'DefaultTemplateService'
|
||||
'DefaultTemplateService',
|
||||
'ServiceContainer',
|
||||
'get_container',
|
||||
'register_default_services',
|
||||
'get_render_service',
|
||||
'get_template_service',
|
||||
'get_task_service'
|
||||
]
|
||||
@@ -111,9 +111,9 @@ class DefaultRenderService(RenderService):
|
||||
logger.info("Executing FFmpeg: %s", " ".join(args))
|
||||
|
||||
try:
|
||||
# 执行FFmpeg进程
|
||||
# 执行FFmpeg进程 (使用构建器已经包含的参数)
|
||||
process = subprocess.run(
|
||||
["ffmpeg", "-progress", "-", "-loglevel", "error"] + args[1:],
|
||||
args,
|
||||
stderr=subprocess.PIPE,
|
||||
**subprocess_args(True)
|
||||
)
|
||||
|
||||
117
services/service_container.py
Normal file
117
services/service_container.py
Normal file
@@ -0,0 +1,117 @@
|
||||
"""
|
||||
服务容器模块 - 提供线程安全的服务实例管理
|
||||
"""
|
||||
import threading
|
||||
from typing import Dict, Type, TypeVar, Optional
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
T = TypeVar('T')
|
||||
|
||||
class ServiceContainer:
|
||||
"""线程安全的服务容器,实现依赖注入和单例管理"""
|
||||
|
||||
def __init__(self):
|
||||
self._services: Dict[Type, object] = {}
|
||||
self._factories: Dict[Type, callable] = {}
|
||||
self._lock = threading.RLock()
|
||||
|
||||
def register_singleton(self, service_type: Type[T], factory: callable) -> None:
|
||||
"""注册单例服务工厂"""
|
||||
with self._lock:
|
||||
self._factories[service_type] = factory
|
||||
logger.debug(f"Registered singleton factory for {service_type.__name__}")
|
||||
|
||||
def get_service(self, service_type: Type[T]) -> T:
|
||||
"""获取服务实例(懒加载单例)"""
|
||||
with self._lock:
|
||||
# 检查是否已存在实例
|
||||
if service_type in self._services:
|
||||
return self._services[service_type]
|
||||
|
||||
# 检查是否有工厂方法
|
||||
if service_type not in self._factories:
|
||||
raise ValueError(f"No factory registered for service type: {service_type}")
|
||||
|
||||
# 创建新实例
|
||||
factory = self._factories[service_type]
|
||||
try:
|
||||
instance = factory()
|
||||
self._services[service_type] = instance
|
||||
logger.debug(f"Created new instance of {service_type.__name__}")
|
||||
return instance
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to create instance of {service_type.__name__}: {e}")
|
||||
raise
|
||||
|
||||
def has_service(self, service_type: Type[T]) -> bool:
|
||||
"""检查是否有服务注册"""
|
||||
with self._lock:
|
||||
return service_type in self._factories
|
||||
|
||||
def clear_cache(self, service_type: Optional[Type[T]] = None) -> None:
|
||||
"""清理服务缓存"""
|
||||
with self._lock:
|
||||
if service_type:
|
||||
self._services.pop(service_type, None)
|
||||
logger.debug(f"Cleared cache for {service_type.__name__}")
|
||||
else:
|
||||
self._services.clear()
|
||||
logger.debug("Cleared all service cache")
|
||||
|
||||
# 全局服务容器实例
|
||||
_container: Optional[ServiceContainer] = None
|
||||
_container_lock = threading.Lock()
|
||||
|
||||
def get_container() -> ServiceContainer:
|
||||
"""获取全局服务容器实例"""
|
||||
global _container
|
||||
if _container is None:
|
||||
with _container_lock:
|
||||
if _container is None:
|
||||
_container = ServiceContainer()
|
||||
return _container
|
||||
|
||||
def register_default_services():
|
||||
"""注册默认的服务实现"""
|
||||
from .render_service import DefaultRenderService, RenderService
|
||||
from .template_service import DefaultTemplateService, TemplateService
|
||||
from .task_service import DefaultTaskService, TaskService
|
||||
|
||||
container = get_container()
|
||||
|
||||
# 注册渲染服务
|
||||
container.register_singleton(RenderService, lambda: DefaultRenderService())
|
||||
|
||||
# 注册模板服务
|
||||
def create_template_service():
|
||||
service = DefaultTemplateService()
|
||||
service.load_local_templates()
|
||||
return service
|
||||
container.register_singleton(TemplateService, create_template_service)
|
||||
|
||||
# 注册任务服务(依赖其他服务)
|
||||
def create_task_service():
|
||||
render_service = container.get_service(RenderService)
|
||||
template_service = container.get_service(TemplateService)
|
||||
return DefaultTaskService(render_service, template_service)
|
||||
container.register_singleton(TaskService, create_task_service)
|
||||
|
||||
logger.info("Default services registered successfully")
|
||||
|
||||
# 便捷函数
|
||||
def get_render_service() -> 'RenderService':
|
||||
"""获取渲染服务实例"""
|
||||
from .render_service import RenderService
|
||||
return get_container().get_service(RenderService)
|
||||
|
||||
def get_template_service() -> 'TemplateService':
|
||||
"""获取模板服务实例"""
|
||||
from .template_service import TemplateService
|
||||
return get_container().get_service(TemplateService)
|
||||
|
||||
def get_task_service() -> 'TaskService':
|
||||
"""获取任务服务实例"""
|
||||
from .task_service import TaskService
|
||||
return get_container().get_service(TaskService)
|
||||
@@ -1,4 +1,3 @@
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
from abc import ABC, abstractmethod
|
||||
@@ -12,6 +11,7 @@ from services.render_service import RenderService
|
||||
from services.template_service import TemplateService
|
||||
from util.exceptions import TaskError, TaskValidationError
|
||||
from util import api, oss
|
||||
from util.json_utils import safe_json_loads
|
||||
from telemetry import get_tracer
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -133,11 +133,11 @@ class DefaultTaskService(TaskService):
|
||||
task_params_str = task_info.get("taskParams", "{}")
|
||||
span.set_attribute("task_params", task_params_str)
|
||||
|
||||
try:
|
||||
task_params = json.loads(task_params_str)
|
||||
task_params_orig = json.loads(task_params_str)
|
||||
except json.JSONDecodeError as e:
|
||||
raise TaskValidationError(f"Invalid task params JSON: {e}")
|
||||
task_params = safe_json_loads(task_params_str, {})
|
||||
task_params_orig = safe_json_loads(task_params_str, {})
|
||||
|
||||
if not task_params:
|
||||
raise TaskValidationError("Invalid or empty task params JSON")
|
||||
|
||||
# 并行下载资源
|
||||
self._download_resources(task_params)
|
||||
@@ -192,14 +192,34 @@ class DefaultTaskService(TaskService):
|
||||
|
||||
def _download_resources(self, task_params: Dict[str, Any]):
|
||||
"""并行下载资源"""
|
||||
with ThreadPoolExecutor(max_workers=8) as executor:
|
||||
from config.settings import get_ffmpeg_config
|
||||
config = get_ffmpeg_config()
|
||||
|
||||
download_futures = []
|
||||
|
||||
with ThreadPoolExecutor(max_workers=config.max_download_workers) as executor:
|
||||
for param_list in task_params.values():
|
||||
if isinstance(param_list, list):
|
||||
for param in param_list:
|
||||
url = param.get("url", "")
|
||||
if url.startswith("http"):
|
||||
_, filename = os.path.split(url)
|
||||
executor.submit(oss.download_from_oss, url, filename, True)
|
||||
future = executor.submit(oss.download_from_oss, url, filename, True)
|
||||
download_futures.append((future, url, filename))
|
||||
|
||||
# 等待所有下载完成,并记录失败的下载
|
||||
failed_downloads = []
|
||||
for future, url, filename in download_futures:
|
||||
try:
|
||||
result = future.result(timeout=30) # 30秒超时
|
||||
if not result:
|
||||
failed_downloads.append((url, filename))
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to download {url}: {e}")
|
||||
failed_downloads.append((url, filename))
|
||||
|
||||
if failed_downloads:
|
||||
logger.warning(f"Failed to download {len(failed_downloads)} resources: {[f[1] for f in failed_downloads]}")
|
||||
|
||||
def _parse_video_source(self, source: str, task_params: Dict[str, Any],
|
||||
template_info: Dict[str, Any]) -> tuple[Optional[str], Dict[str, Any]]:
|
||||
|
||||
Reference in New Issue
Block a user