1

When trying to create simple coap server with asyncronous function and asyncio.run it return Event loop is closed. Code below:

import aiocoap
import aiocoap.resource as resource


class CoAPServer(resource.Resource):
    def __init__(self) -> None:
        super().__init__()

    async def render_get(self, request):
        print("Received GET request ...")
        return aiocoap.Message(code=aiocoap.GET, payload="hello friend".encode('utf8'))

    async def render_post(self, request):
        print("Received POST request ...")
        return aiocoap.Message(code=aiocoap.CHANGED, payload="that's me".encode('utf8'))

async def main():
    root = resource.Site()
    root.add_resource(['demo'], CoAPServer)
    task = asyncio.create_task(aiocoap.Context.create_server_context(root, bind=('127.0.0.1', 5683)))
    await task

if __name__ == "__main__":
    asyncio.run(main())

Gives this error:

Exception ignored in: <function RecvmsgSelectorDatagramTransport.__del__ at 0x7f9a04c57310>
Traceback (most recent call last):
  File "/usr/local/lib/python3.8/dist-packages/aiocoap/util/asyncio/recvmsg.py", line 95, in __del__
    self.close()
  File "/usr/local/lib/python3.8/dist-packages/aiocoap/util/asyncio/recvmsg.py", line 83, in close
    self._loop.call_soon(self._protocol.connection_lost, None)
  File "/usr/lib/python3.8/asyncio/base_events.py", line 719, in call_soon
    self._check_closed()
  File "/usr/lib/python3.8/asyncio/base_events.py", line 508, in _check_closed
    raise RuntimeError('Event loop is closed')
RuntimeError: Event loop is closed

Instead, if i use get_event_loop().run_forever() which is not recommended as per the docs

Application developers should typically use the high-level asyncio functions, such as asyncio.run(), and should rarely need to reference the loop object or call its methods. This section is intended mostly for authors of lower-level code, libraries, and frameworks, who need finer control over the event loop behavior.

if __name__ == "__main__":
    asyncio.get_event_loop().run_forever()

it works. Currently using python3.8.10 in wsl

2 Answers2

0

This is an issue resulting from aiocoap still using (and, in some places, using badly) idioms to support Python 3.7 or (in obsoleted parts) even previous versions.

I'm aware asyncio.run() is preferred, but until the next aiocoap release (in which I plan to update the examples too), the old idiom is what works best across the range of supported Python versions.

chrysn
  • 810
  • 6
  • 19
  • Sorry did not meant to be obnoxious with the best practices i cited, i was just trying to figure out if i was to blame, the docs or something else. Really appreciate your work! – Giulio Barabino Nov 16 '21 at 16:13
  • 1
    Not obnoxious at all, it is a valid point, and the blame is with me still slopping on adopting modern asyncio. – chrysn Nov 16 '21 at 16:16
  • The latest status (not released yet, but in the master branch) fixed the issue you're pointing out and a few others; please open a bug if you find anything that acts up when used with `asyncio.run()` now. (Or anything that acts up, really :-) ) – chrysn Nov 29 '21 at 16:03
0

The code with asyncio.run(main()) works fine on a Unix system. So, it's most likely an issue with how aiocoap deals with the event loop in a WSL environment. For now, you're better off using asyncio.get_event_loop().run_forever() until the maintainers patches the library.

Redowan Delowar
  • 1,580
  • 1
  • 14
  • 36
  • There is some weirdness in `asyncio.run()` even on Linux systems, eg. when interrupting programs with Ctrl-C. I think this stems from how I had tried to work around some of the problematic aspects of pre-`.run()` asyncio, eg. through manual handling of KeyboardInterrupt. – chrysn Nov 23 '21 at 07:41