mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-09-05 15:38:19 +08:00
fix: 保持搜索线程任务的请求上下文 (#6451)
This commit is contained in:
@@ -13,7 +13,7 @@ from threading import Lock
|
||||
from typing import Dict, Optional
|
||||
|
||||
from app.foundation.singleton import Singleton
|
||||
from app.runtime.execution import OwnedThreadPoolExecutor
|
||||
from app.runtime.execution import OwnedThreadPoolExecutor, submit_with_context
|
||||
from app.runtime.log import logger
|
||||
from app.runtime.reload import ConfigReloadMixin
|
||||
from app.runtime.settings import get_runtime_setting
|
||||
@@ -74,7 +74,7 @@ def enable_doh(enable: bool) -> bool:
|
||||
executor = _get_executor_locked()
|
||||
# 一次解析的任务必须在同一临界区提交完,避免关闭过程中部分任务落入新线程池
|
||||
futures = [
|
||||
executor.submit(_doh_query, resolver, host)
|
||||
submit_with_context(executor, _doh_query, resolver, host)
|
||||
for resolver in _doh_setting("DOH_RESOLVERS").split(",")
|
||||
]
|
||||
for future in as_completed(futures):
|
||||
|
||||
+14
-6
@@ -11,7 +11,7 @@ from typing import AsyncIterator, Any, Awaitable, Callable, Dict, Iterable, Tupl
|
||||
from typing import List, Optional
|
||||
from unicodedata import normalize
|
||||
|
||||
from app.runtime.execution import run_in_threadpool
|
||||
from app.runtime.execution import run_in_threadpool, submit_with_context
|
||||
from app.chain import ChainBase
|
||||
from app.chain.media import MediaChain
|
||||
from app.runtime.config import global_vars
|
||||
@@ -1291,7 +1291,11 @@ class SearchChain(ChainBase):
|
||||
)
|
||||
with ThreadPoolExecutor(max_workers=max_workers) as executor:
|
||||
all_tasks = {
|
||||
executor.submit(__do_site_filter, site_torrent_list): site_key
|
||||
submit_with_context(
|
||||
executor,
|
||||
__do_site_filter,
|
||||
site_torrent_list,
|
||||
): site_key
|
||||
for site_key, site_torrent_list in site_torrents.items()
|
||||
}
|
||||
for future in as_completed(all_tasks):
|
||||
@@ -2365,10 +2369,14 @@ class SearchChain(ChainBase):
|
||||
search_page = search_pages[page_index]
|
||||
# 关键字已按 area 统一解析(imdbid 场景使用 imdb 标识),站点调用无需再分支
|
||||
search_keyword = mediainfo.imdb_id if area == "imdbid" and mediainfo else keyword
|
||||
task = executor.submit(self.search_site_torrents, site=site,
|
||||
keyword=search_keyword,
|
||||
mtype=mediainfo.type if mediainfo else mtype,
|
||||
page=search_page)
|
||||
task = submit_with_context(
|
||||
executor,
|
||||
self.search_site_torrents,
|
||||
site=site,
|
||||
keyword=search_keyword,
|
||||
mtype=mediainfo.type if mediainfo else mtype,
|
||||
page=search_page,
|
||||
)
|
||||
pending_tasks[task] = (site, page_index, search_page, search_keyword)
|
||||
|
||||
for site in indexer_sites:
|
||||
|
||||
@@ -2,8 +2,8 @@ import asyncio
|
||||
import inspect
|
||||
import threading
|
||||
import time
|
||||
from concurrent.futures import Future, ThreadPoolExecutor, wait
|
||||
from contextvars import copy_context
|
||||
from concurrent.futures import Executor, Future, ThreadPoolExecutor, wait
|
||||
from contextvars import Context, copy_context
|
||||
from functools import partial, wraps
|
||||
from typing import Any, Callable, TypeVar, cast
|
||||
|
||||
@@ -15,6 +15,22 @@ TaskResult = TypeVar("TaskResult")
|
||||
ExecutorResult = TypeVar("ExecutorResult")
|
||||
|
||||
|
||||
def submit_with_context(
|
||||
executor: Executor,
|
||||
func: Callable[..., ExecutorResult],
|
||||
/,
|
||||
*args: Any,
|
||||
**kwargs: Any,
|
||||
) -> Future[ExecutorResult]:
|
||||
"""从空线程上下文提交任务,并在执行时恢复调用方的独立上下文快照。"""
|
||||
context = copy_context()
|
||||
|
||||
def submit() -> Future[ExecutorResult]:
|
||||
return executor.submit(context.run, func, *args, **kwargs)
|
||||
|
||||
return Context().run(submit)
|
||||
|
||||
|
||||
class OwnedThreadPoolExecutor(ThreadPoolExecutor):
|
||||
"""
|
||||
追踪已接受 Future,并提供可重试的有界关闭合同。
|
||||
|
||||
Reference in New Issue
Block a user