# Buggy code
async def watch_objs(
    *,
    settings: configuration.OperatorSettings,
    resource: resources.Resource,
    namespace: Optional[str] = None,
    timeout: Optional[float] = None,
    since: Optional[str] = None,
    context: Optional[auth.APIContext] = None,  # injected by the decorator
    freeze_waiter: asyncio_Future,
) -> AsyncIterator[bodies.RawInput]:
    """
    Watch objects of a specific resource type.

    The cluster-scoped call is used in two cases:

    * The resource itself is cluster-scoped, and namespacing makes not sense.
    * The operator serves all namespaces for the namespaced custom resource.

    Otherwise, the namespace-scoped call is used:

    * The resource is namespace-scoped AND operator is namespaced-restricted.
    """
    if context is None:
        raise RuntimeError("API instance is not injected by the decorator.")

    is_namespaced = await discovery.is_namespaced(resource=resource, context=context)
    namespace = namespace if is_namespaced else None

    params: Dict[str, str] = {}
    params["watch"] = "true"
    if since is not None:
        params["resourceVersion"] = since
    if timeout is not None:
        params["timeoutSeconds"] = str(timeout)

    # Talk to the API and initiate a streaming response.
    response = await context.session.get(
        url=resource.get_url(server=context.server, namespace=namespace, params=params),
        timeout=aiohttp.ClientTimeout(
            total=settings.watching.client_timeout,
            sock_connect=settings.watching.connect_timeout,
        ),
    )
    response.raise_for_status()

    # Stream the parsed events from the response until it is closed server-side,
    # or until it is closed client-side by the freeze-waiting future's callbacks.
    response_close_callback = lambda _: response.close()
    freeze_waiter.add_done_callback(response_close_callback)
    try:
        async with response:
            async for line in _iter_jsonlines(response.content):
                raw_input = cast(bodies.RawInput, json.loads(line.decode("utf-8")))
                yield raw_input
    except (
        aiohttp.ClientConnectionError,
        aiohttp.ClientPayloadError,
        asyncio.TimeoutError,
    ):
        pass
    finally:
        freeze_waiter.remove_done_callback(response_close_callback)


# Traceback (aiohttp.client_exceptions.ServerDisconnectedError)
[2020-05-25 10:44:44,924] kopf.reactor.running [ERROR ] Root task 'watcher of pods' is failed:
Traceback (most recent call last):
File "/usr/local/lib/python3.7/dist-packages/kopf/reactor/running.py", line 453, in _root_task_checker
await coro
File "/usr/local/lib/python3.7/dist-packages/kopf/reactor/queueing.py", line 109, in watcher
async for raw_event in stream:
File "/usr/local/lib/python3.7/dist-packages/kopf/clients/watching.py", line 75, in infinite_watch
async for raw_event in stream:
File "/usr/local/lib/python3.7/dist-packages/kopf/clients/watching.py", line 112, in streaming_watch
async for raw_event in stream:
File "/usr/local/lib/python3.7/dist-packages/kopf/clients/watching.py", line 146, in continuous_watch
async for raw_input in stream:
File "/usr/local/lib/python3.7/dist-packages/kopf/clients/auth.py", line 78, in wrapper
async for item in fn(*args, **kwargs, context=context):
File "/usr/local/lib/python3.7/dist-packages/kopf/clients/watching.py", line 215, in watch_objs
sock_connect=settings.watching.connect_timeout,
File "/usr/local/lib/python3.7/dist-packages/aiohttp/client.py", line 504, in _request
await resp.start(conn)
File "/usr/local/lib/python3.7/dist-packages/aiohttp/client_reqrep.py", line 847, in start
message, payload = await self._protocol.read() # type: ignore # noqa
File "/usr/local/lib/python3.7/dist-packages/aiohttp/streams.py", line 591, in read
await self._waiter
aiohttp.client_exceptions.ServerDisconnectedError

# Fixed code
async def watch_objs(
    *,
    settings: configuration.OperatorSettings,
    resource: resources.Resource,
    namespace: Optional[str] = None,
    timeout: Optional[float] = None,
    since: Optional[str] = None,
    context: Optional[auth.APIContext] = None,  # injected by the decorator
    freeze_waiter: asyncio_Future,
) -> AsyncIterator[bodies.RawInput]:
    """
    Watch objects of a specific resource type.

    The cluster-scoped call is used in two cases:

    * The resource itself is cluster-scoped, and namespacing makes not sense.
    * The operator serves all namespaces for the namespaced custom resource.

    Otherwise, the namespace-scoped call is used:

    * The resource is namespace-scoped AND operator is namespaced-restricted.
    """
    if context is None:
        raise RuntimeError("API instance is not injected by the decorator.")

    is_namespaced = await discovery.is_namespaced(resource=resource, context=context)
    namespace = namespace if is_namespaced else None

    params: Dict[str, str] = {}
    params["watch"] = "true"
    if since is not None:
        params["resourceVersion"] = since
    if timeout is not None:
        params["timeoutSeconds"] = str(timeout)

    # Stream the parsed events from the response until it is closed server-side,
    # or until it is closed client-side by the freeze-waiting future's callbacks.
    try:
        response = await context.session.get(
            url=resource.get_url(
                server=context.server, namespace=namespace, params=params
            ),
            timeout=aiohttp.ClientTimeout(
                total=settings.watching.client_timeout,
                sock_connect=settings.watching.connect_timeout,
            ),
        )
        response.raise_for_status()

        response_close_callback = lambda _: response.close()
        freeze_waiter.add_done_callback(response_close_callback)
        try:
            async with response:
                async for line in _iter_jsonlines(response.content):
                    raw_input = cast(bodies.RawInput, json.loads(line.decode("utf-8")))
                    yield raw_input
        finally:
            freeze_waiter.remove_done_callback(response_close_callback)

    except (
        aiohttp.ClientConnectionError,
        aiohttp.ClientPayloadError,
        asyncio.TimeoutError,
    ):
        pass