停止 docker-py 事件流迭代

Stop docker-py events stream iteration

我如何请求 docker-py 事件停止 events 流迭代?例如,我想停下来观看码头工人活动。

from docker import Client


client = Client(base_url='unix://var/run/docker.sock')
events = client.events(decode=True)

for event in events:
    print(event)

print('exited')

client.events() return 生成器构建 here

client.events() 生成器正在阻塞 unix 套接字 recv 调用。如果您不能等到下一个事件并且 break 退出循环,则需要中断套接字。

不幸的是,我找不到通过 docker-py 执行此操作的干净方法。我发现的唯一方法需要 using/overriding 私有方法,这当然很脆弱。如果您正在寻找一个可靠的解决方案,我建议您直接进行 api 调用,然后您可以自由地在套接字上设置自己的超时或在非阻塞模式下使用它。

话虽这么说,要直接回答这个问题,这里有一种方法可以修补 Client class 以将 api 响应作为 属性 添加到生成器events().

返回
from docker import Client

class CustomGenerator(object):
    def __init__(self, stream, response, decode):
        self.stream = stream
        self.response = response
        self.decode = decode

    def __iter__(self):
        for item in super(CustomClient, self.stream).\
                _stream_helper(self.response, self.decode):
            yield item

class CustomClient(Client):
    def _stream_helper(self, response, decode=False):
        return CustomGenerator(self, response, decode)

收到响应后,您可以关闭套接字,这将在生成器中引发异常。在这个例子中,我使用一个线程在 5 秒后停止监听。

from threading import Timer
import requests
import socket

client = CustomClient(base_url="unix://var/run/docker.sock")
events = client.events()

def listen_for_events():
    print("listening")

    try:
        for event in events:
            print(event)
    except requests.packages.urllib3.exceptions.ProtocolError:
        pass

    print("done listening")

def stop_listening():
    sock = client._get_raw_response_socket(events.response)
    sock.shutdown(socket.SHUT_RDWR)

Timer(5, stop_listening).start()

listen_for_events()

为了能够中断等待下一个事件,您可以使用 events() 方法的 sinceuntil 参数,通过在两秒的时间范围内监听事件。

from datetime import datetime, timedelta

import docker
client = docker.from_env()

delta = timedelta(seconds=2)
since = datetime.utcnow()
until = datetime.utcnow() + delta
while True:
    for event in client.events(since=since, until=until, decode=True):
        print(event)
    since = until
    until = datetime.utcnow() + delta

由于您等待事件 2 秒,您的执行线程将被阻塞最多 2 秒。因此,如果用户点击 Ctrl+C,脚本将很快终止。