Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Stop docker-py events stream iteration

Tags:

dockerpy

How can i ask to docker-py events to stop events stream iterable ? I want, for exemple, simply stop to watch dockers 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 generator build here.

like image 883
bux Avatar asked Jun 05 '26 02:06

bux


1 Answers

The client.events() generator is blocking on a unix socket recv call. If you can't wait until the next event and break out of the loop then, you'll need to interrupt the socket.

Unfortunately I couldn't find a clean way to do this via docker-py. The only way I found requires using/overriding private methods which of course is fragile. If you're looking for a robust solution I would recommend making the api call directly and then you're free to set your own timeouts on the socket or use it in non-blocking mode.

With that being said, to directly answer the question here's a way to patch the Client class to add the api response as a property to the generator returned by 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)

Once you have the response you can shutdown the socket which will raise an exception in the generator. In this example I use a thread to stop listening after 5 seconds.

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()
like image 53
gfemec Avatar answered Jun 07 '26 23:06

gfemec