-
Notifications
You must be signed in to change notification settings - Fork 10.2k
增强域名重试机制 (#472) #474
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
增强域名重试机制 (#472) #474
Changes from all commits
6cf0d74
32059dd
a1b9597
60929f9
3355c33
d39cc8b
e695d72
650d271
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| # .github/release.yml | ||
|
|
||
| changelog: | ||
| exclude: | ||
| labels: | ||
| - ignore-for-release | ||
| authors: | ||
| - octocat | ||
| categories: | ||
| - title: 🏕 Features | ||
| labels: | ||
| - '*' | ||
| exclude: | ||
| labels: | ||
| - dependencies | ||
| - title: 👒 Dependencies | ||
| labels: | ||
| - dependencies | ||
| - title: Other Changes | ||
| labels: | ||
| - "*" |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -1221,23 +1221,88 @@ def new_decide_dir(photo, ensure_exists=True) -> str: | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| class AdvancedRetryPlugin(JmOptionPlugin): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| plugin_key = 'advanced-retry' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def __init__(self, option: JmOption): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| super().__init__(option) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| self.retry_config = None | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def invoke(self, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| retry_config, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| **kwargs): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| self.require_param(isinstance(retry_config, dict), '必须配置retry_config为dict') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| self.retry_config = retry_config | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+1231
to
+1233
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Validate required keys and normalize types in Fail fast if keys are missing; coerce to int to avoid surprises later. Apply this diff: - self.require_param(isinstance(retry_config, dict), '必须配置retry_config为dict')
- self.retry_config = retry_config
+ self.require_param(isinstance(retry_config, dict), '必须配置retry_config为dict')
+ required = ('retry_rounds', 'retry_domain_max_times')
+ missing = [k for k in required if k not in retry_config]
+ self.require_param(not missing, f'缺少配置项: {missing}')
+ retry_config['retry_rounds'] = int(retry_config['retry_rounds'])
+ retry_config['retry_domain_max_times'] = int(retry_config['retry_domain_max_times'])
+ self.retry_config = retry_config📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| new_jm_client: Callable = self.option.new_jm_client | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def hook_new_jm_client(*args, **kwargs): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| client: AbstractJmClient = new_jm_client(*args, **kwargs) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| client: JmcomicClient = new_jm_client(*args, **kwargs) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| client.domain_retry_strategy = self.request_with_retry | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| client.domain_req_failed_counter = {} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from threading import Lock | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| client.domain_counter_lock = Lock() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return client | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| self.option.new_jm_client = hook_new_jm_client | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def request_with_retry(self, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| client, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| request, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| url, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| is_image, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| client: AbstractJmClient, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| request: Callable, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| url: str, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| is_image: bool, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| **kwargs, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pass | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 实现如下域名重试机制: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - 对域名列表轮询请求,配置:retry_rounds | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - 限制单个域名最大失败次数,配置:retry_domain_max_times | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - 轮询域名列表前,根据历史失败次数对域名列表排序,失败多的后置 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def do_request(domain): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| url_to_use = url | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if url_to_use.startswith('/'): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # path → url | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| url_to_use = client.of_api_url(url, domain) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| client.update_request_with_specify_domain(kwargs, domain, is_image) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| jm_log(client.log_topic(), client.decode(url_to_use)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| elif is_image: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # 图片url | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| client.update_request_with_specify_domain(kwargs, None, is_image) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| resp = request(url_to_use, **kwargs) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| resp = client.raise_if_resp_should_retry(resp, is_image) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return resp | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+1260
to
+1274
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Use per-attempt kwargs and reset failure count on success.
Apply this diff: - def do_request(domain):
- url_to_use = url
+ def do_request(domain):
+ # Use a fresh kwargs for each attempt
+ local_kwargs = dict(kwargs)
+ url_to_use = url
if url_to_use.startswith('/'):
# path → url
url_to_use = client.of_api_url(url, domain)
- client.update_request_with_specify_domain(kwargs, domain, is_image)
+ client.update_request_with_specify_domain(local_kwargs, domain, is_image)
jm_log(client.log_topic(), client.decode(url_to_use))
elif is_image:
# 图片url
- client.update_request_with_specify_domain(kwargs, None, is_image)
+ client.update_request_with_specify_domain(local_kwargs, None, is_image)
- resp = request(url_to_use, **kwargs)
+ resp = request(url_to_use, **local_kwargs)
resp = client.raise_if_resp_should_retry(resp, is_image)
+ # Success → clear failed counter for this domain
+ with client.domain_counter_lock:
+ client.domain_req_failed_counter[domain] = 0
return resp📝 Committable suggestion
Suggested change
🧰 Tools🪛 Ruff (0.12.2)1266-1266: (F405) 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| retry_domain_max_times: int = self.retry_config['retry_domain_max_times'] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| retry_rounds: int = self.retry_config['retry_rounds'] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for rindex in range(retry_rounds): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| domain_list = self.get_sorted_domain(client, retry_domain_max_times) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for i, domain in enumerate(domain_list): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if self.failed_count(client, domain) >= retry_domain_max_times: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| continue | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return do_request(domain) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| except Exception as e: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from common import traceback_print_exec | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| traceback_print_exec() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| jm_log('req.error', str(e)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| self.update_failed_count(client, domain) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
coderabbitai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return client.fallback(request, url, 0, 0, is_image, **kwargs) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def get_sorted_domain(self, client: JmcomicClient, times): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| domain_list = client.get_domain_list() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return sorted( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| filter(lambda d: self.failed_count(client, d) < times, domain_list), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| key=lambda d: self.failed_count(client, d) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # noinspection PyUnresolvedReferences | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def update_failed_count(self, client: AbstractJmClient, domain: str): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| with client.domain_counter_lock: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| client.domain_req_failed_counter[domain] = self.failed_count(client, domain) + 1 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @staticmethod | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def failed_count(client: JmcomicClient, domain: str) -> int: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # noinspection PyUnresolvedReferences | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return client.domain_req_failed_counter.get(domain, 0) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Add newline at EOF; confirm retry interplay.
Add final newline. Also verify that client.retry_times is intentionally unused when advanced-retry is active to avoid confusion.
🏁 Script executed:
Length of output: 3936
🏁 Script executed:
Length of output: 842
🏁 Script executed:
Length of output: 29
Add final newline to assets/option/option_test_api.yml. Confirmed that when advanced-retry (domain_retry_strategy) is set, JmcomicClient always uses request_with_retry and ignores client.retry_times, so retry_times is intentionally unused.
🧰 Tools
🪛 YAMLlint (1.37.1)
[error] 34-34: no new line character at the end of file
(new-line-at-end-of-file)
🤖 Prompt for AI Agents