这里我们遇到了一个有趣的情况,这种情况不应该发生,并且似乎是由退避引起的。在退避文档中找不到相关信息,也找不到相关问题。
此代码在带有 Nginx 和 Gunicorn(启用 9 个工作线程)的 Ubuntu 服务器中使用 Python 3.9 运行:
# this runs in Ubuntu server with Nginx and gunicorn (9 workers enabled) with Python 3.9
import backoff # backoff version 2.2.1
from multiprocessing.dummy import Pool as ThreadPool
tries = 0
MAX_RETRIES = 5
@backoff.on_exception(backoff.constant, ValueError, interval=0.5, max_tries=MAX_RETRIES)
def do_stuff_with_backoff_retry(var_1):
global tries
tries = tries + 1
try:
# do stuff with var_1 that may generate exception and return something if successfully done
something = var_1
return something
except:
msg = f'Error at do_stuff_with_backoff_retry function'
print(msg)
raise ValueError(msg)
def controller_func(var_1):
global tries
tries = 0
try:
result = do_stuff_with_backoff_retry(var_1)
msg = f'[Try {tries} of {MAX_RETRIES}] success at do_stuff_with_backoff_retry function'
print(msg)
return result
except:
print(f'Failed at do_stuff_with_backoff_retry function')
def do_with_threading():
list_of_data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
pool = ThreadPool(15)
results2 = pool.map(controller_func, list_of_data)
pool.close()
pool.join()
print(f'results2: {results2}')
如果在极少数情况下以
controller_func(5)
(使用 var_1 = 5
或任何其他值)开始处理,我会收到以下成功消息:
[Try 6 of 5] success at do_stuff_with_backoff_retry function
它不应该得到
Try 6 of 5
,因为 5 是允许的最大尝试次数。
在更罕见的情况下,我会得到
Try 7 of 5
。
如果处理是从
do_with_threading()
开始的,在常见情况下我会收到类似以下内容的消息:
[Try 11 of 5] success at do_stuff_with_backoff_retry function
[Try 15 of 5] success at do_stuff_with_backoff_retry function
[Try 13 of 5] success at do_stuff_with_backoff_retry function
查看其他记录的数据似乎后台正在重试尊重
MAX_RETRIES = 5
,但似乎tries = 0
处的controller_func(var_1)
无法正常工作。
还是我做错了什么?
我为克服这种情况制定的解决方案是使用 Redis。
在controller_func处将值
0
(零)设置为Redis中的键,然后,在do_stuff_with_backoff_retry开始时读取键,将其转换为整数,该值增加1
并再次保存到Redis中。
键名有一个与正在处理的文件关联的可变部分,对于每个线程来说都是唯一的,确保永远不会发生键名冲突。
例如:
文件到进程:
dsjfsdo8wejroscmeiuwerl.txt
key_name = f'Counter_at_redis_for__{file_to_process}'