@@ -1221,23 +1221,88 @@ def new_decide_dir(photo, ensure_exists=True) -> str:
1221
1221
class AdvancedRetryPlugin (JmOptionPlugin ):
1222
1222
plugin_key = 'advanced-retry'
1223
1223
1224
+ def __init__ (self , option : JmOption ):
1225
+ super ().__init__ (option )
1226
+ self .retry_config = None
1227
+
1224
1228
def invoke (self ,
1225
1229
retry_config ,
1226
1230
** kwargs ):
1231
+ self .require_param (isinstance (retry_config , dict ), '必须配置retry_config为dict' )
1232
+ self .retry_config = retry_config
1233
+
1227
1234
new_jm_client : Callable = self .option .new_jm_client
1228
1235
1229
1236
def hook_new_jm_client (* args , ** kwargs ):
1230
- client : AbstractJmClient = new_jm_client (* args , ** kwargs )
1237
+ client : JmcomicClient = new_jm_client (* args , ** kwargs )
1231
1238
client .domain_retry_strategy = self .request_with_retry
1239
+ client .domain_req_failed_counter = {}
1240
+ from threading import Lock
1241
+ client .domain_counter_lock = Lock ()
1232
1242
return client
1233
1243
1234
1244
self .option .new_jm_client = hook_new_jm_client
1235
1245
1236
1246
def request_with_retry (self ,
1237
- client ,
1238
- request ,
1239
- url ,
1240
- is_image ,
1247
+ client : AbstractJmClient ,
1248
+ request : Callable ,
1249
+ url : str ,
1250
+ is_image : bool ,
1241
1251
** kwargs ,
1242
1252
):
1243
- pass
1253
+ """
1254
+ 实现如下域名重试机制:
1255
+ - 对域名列表轮询请求,配置:retry_rounds
1256
+ - 限制单个域名最大失败次数,配置:retry_domain_max_times
1257
+ - 轮询域名列表前,根据历史失败次数对域名列表排序,失败多的后置
1258
+ """
1259
+
1260
+ def do_request (domain ):
1261
+ url_to_use = url
1262
+ if url_to_use .startswith ('/' ):
1263
+ # path → url
1264
+ url_to_use = client .of_api_url (url , domain )
1265
+ client .update_request_with_specify_domain (kwargs , domain , is_image )
1266
+ jm_log (client .log_topic (), client .decode (url_to_use ))
1267
+ elif is_image :
1268
+ # 图片url
1269
+ client .update_request_with_specify_domain (kwargs , None , is_image )
1270
+
1271
+ resp = request (url_to_use , ** kwargs )
1272
+ resp = client .raise_if_resp_should_retry (resp , is_image )
1273
+ return resp
1274
+
1275
+ retry_domain_max_times : int = self .retry_config ['retry_domain_max_times' ]
1276
+ retry_rounds : int = self .retry_config ['retry_rounds' ]
1277
+ for rindex in range (retry_rounds ):
1278
+ domain_list = self .get_sorted_domain (client , retry_domain_max_times )
1279
+ for i , domain in enumerate (domain_list ):
1280
+ if self .failed_count (client , domain ) >= retry_domain_max_times :
1281
+ continue
1282
+
1283
+ try :
1284
+ return do_request (domain )
1285
+ except Exception as e :
1286
+ from common import traceback_print_exec
1287
+ traceback_print_exec ()
1288
+ jm_log ('req.error' , str (e ))
1289
+ self .update_failed_count (client , domain )
1290
+
1291
+ return client .fallback (request , url , 0 , 0 , is_image , ** kwargs )
1292
+
1293
+ def get_sorted_domain (self , client : JmcomicClient , times ):
1294
+ domain_list = client .get_domain_list ()
1295
+ return sorted (
1296
+ filter (lambda d : self .failed_count (client , d ) < times , domain_list ),
1297
+ key = lambda d : self .failed_count (client , d )
1298
+ )
1299
+
1300
+ # noinspection PyUnresolvedReferences
1301
+ def update_failed_count (self , client : AbstractJmClient , domain : str ):
1302
+ with client .domain_counter_lock :
1303
+ client .domain_req_failed_counter [domain ] = self .failed_count (client , domain ) + 1
1304
+
1305
+ @staticmethod
1306
+ def failed_count (client : JmcomicClient , domain : str ) -> int :
1307
+ # noinspection PyUnresolvedReferences
1308
+ return client .domain_req_failed_counter .get (domain , 0 )
0 commit comments