TL;博士
如何在单独的进程中安全地await
执行函数(将str
和int
作为参数,不需要任何其他上下文)?
很长的故事
我有aiohtto.web
使用Boost.Python
包装器进行C++
扩展的 Web API,在gunicorn
(我计划将其部署在 Heroku 上)下运行,由locust
.
关于扩展:它只有一个执行非阻塞操作的函数——接受一个字符串(和一个用于超时管理的整数),用它进行一些计算并返回一个新字符串。对于每个输入字符串,它只有一个可能的输出(超时除外,但在这种情况下,C++
Boost.Python 必须引发异常并将其转换为与 Python 兼容的输出)。
简而言之,特定 URL 的处理程序执行以下代码:
res = await loop.run_in_executor(executor, func, *args)
executor
C++ 扩展模块中的ProcessPoolExecutor
实例和func
-function在哪里。(在实际项目中,这段代码在类的协程方法中,而且func
——classmethod
它只执行C++
函数并返回结果)
错误捕捉
当一个新请求到达时,我提取它的 POST 数据request.post()
,然后将它的数据存储到名为的自定义类的实例中Call
(因为我不知道如何以另一种方式命名它)。因此该call
对象包含所有输入数据(字符串)、请求接收时间和id
请求附带的唯一性。
然后它继续到名为Handler
的类(不是aiohttp
请求处理程序),将它的输入传递给另一个类的loop.run_in_executor
内部方法。但是Handler
有一个像中间件一样工作的日志系统——读取每个传入call
对象的 id 和接收时间,并用一条消息记录它,告诉你它刚刚开始执行、成功执行或遇到麻烦。此外,Handler
将try/except
所有错误保存并存储在call
对象中,以便日志记录中间件知道发生了什么错误,或者返回了什么输出扩展
测试
我有一个单元测试,它只在里面创建了 256 个协程,里面有这段代码,执行器有 256 个工作人员,它运行良好。
但是当用 Locust 进行测试时,就会出现问题。我使用 4 个 Gunicorn worker 和 4 个 executor worker 进行这种测试。有时应用程序刚开始返回错误的输出。
My LocustTaskSet
被配置为使用所有可用信息记录每个故障响应:输出字符串、错误字符串、输入字符串(也由应用程序返回)、id。所有模拟请求都是相同的,但id
对每个请求都是唯一的。
max_requests
将 Gunicorn 的选项设置为100
requests时情况会更好,但仍然会出现故障。
有趣的是,有时我可以通过简单地停止和启动 Locust 的测试来触发“错误输出”期间。
我需要 100% 保证我的 Web API 按预期工作。
更新和解决方案
刚刚让我的队友检查 C++ 代码 - 问题出在全局变量中。在某种程度上,这对 256 个并行协程来说不是问题,但对 Gunicorn 来说却是。