【发布时间】:2021-03-01 18:45:10
【问题描述】:
我在基于aiohttp 的应用程序中使用python docker SDK。我的目标是在请求到来时启动一个容器,等到它完成所有工作并返回响应。我想同时处理很多这样的请求。
我在分离模式下运行容器,所以问题不在于启动容器本身。问题是如何定义容器何时完成工作。 Container docker 包的实例有一个方法 wait() 但它是阻塞的,所以我不能“像那样”使用它。所以我想出了别的办法:我启动一个容器,创建新的 asyncio 任务,并且(在那个任务中)我正在检查容器是否改变了它的状态。它看起来或多或少是这样的:
import docker
import asyncio
import time
def wait_for_finish(event, container):
try:
container.reload()
timeout = time.time() + 600
while time.time() < timeout:
if container.status == 'running' or container.status == 'created':
await asyncio.sleep(0.5)
try:
container.reload()
except requests.exceptions.HTTPError:
break
else:
break
finally:
event.set()
docker_client = docker.from_env()
container = docker_client.containers.run(**kwargs)
event = asyncio.Event()
asyncio.create_task(
wait_for_finish(event, container)
)
await event.wait()
event.clear()
这很简单,但效果很好。但我的问题是:这种等待容器完成的“虚拟”方式(状态不同于running 或created)是一个好方法吗?说实话我不知道喜欢这个解决方案,因为几个原因,我认为这种“等待”有问题,但我不知道究竟是什么......
我知道诸如aiodocker 或run_in_executor/threading 之类的解决方案,甚至用subprocess 替换docker sdk,但现在我想使用 - 如果可能的话 - 组合asyncio 和 docker sdk 没有例如阅读
编辑
我最终得到了这样的解决方案:我通过 aiohttp 直接向 Docker API 发出异步请求,这允许我异步使用提到的 wait() 方法:
await docker_socket_session.post(f'http://localhost/containers/{container_id}/wait', timeout=timeout)
它运行良好,至少目前我没有看到任何有意义的缺点。
感谢您的帮助
【问题讨论】:
-
如果应用程序阻塞在这个 docker 逻辑上,这里使用
asyncio有什么意义? -
@gold_cy ,提供的示例不会阻止在有意义的时间内禁用整个应用程序的含义。
container.reload()阻止,因为它向 docker api 发出同步请求,但我想我可以用直接向 docker api 的异步请求替换这一行,以检查容器的当前状态。我的问题是 - ** 在循环中显式检查容器的当前状态这样的方法在应用程序效率方面是一个很好的解决方案吗? **
标签: python docker python-asyncio aiohttp