DongMaster
DongMaster

Reputation: 23

How can I make a non-blocking UDP server and a periodic task in the same script?

I am trying to make a UDP server and next to it a periodic task that updates a global variable every 5 minutes.

But the problem is that my UDP server and my task part blocks the rest of the code (because I use while True:).

I was looking at this example: https://docs.python.org/3/library/asyncio-protocol.html#asyncio-udp-echo-server-protocol

import asyncio


class EchoServerProtocol:
    def connection_made(self, transport):
        self.transport = transport

    def datagram_received(self, data, addr):
        message = data.decode()
        print('Received %r from %s' % (message, addr))
        print('Send %r to %s' % (message, addr))
        self.transport.sendto(data, addr)


async def main():
    print("Starting UDP server")

    # Get a reference to the event loop as we plan to use
    # low-level APIs.
    loop = asyncio.get_running_loop()

    # One protocol instance will be created to serve all
    # client requests.
    transport, protocol = await loop.create_datagram_endpoint(
        lambda: EchoServerProtocol(),
        local_addr=('127.0.0.1', 9999))

    try:
        await asyncio.sleep(3600)  # Serve for 1 hour.
    finally:
        transport.close()


asyncio.run(main())

I see in the example that they run this for an hour. But what if I wanted to run it indefinitely? I played with run_forever(), but I don't understand how it works.

I also don't understand how to make a periodic task that doesn't use while True: at the same time.

Is this possible?

Upvotes: 0

Views: 1022

Answers (2)

gre_gor
gre_gor

Reputation: 6764

Instead waiting for an hour, just make an infinite loop which executes your periodic task.

Replace

await asyncio.sleep(3600)

with

while True:
    print("do something every 5 minutes", datetime.datetime.now())
    await asyncio.sleep(5*60)

Upvotes: 0

Paul Cornelius
Paul Cornelius

Reputation: 10946

Replace your asyncio.sleep(3600) with a wait for an asyncio.Event that never happens. That will suspend the task forever but leave the event loop running. The only way to terminate the program is with Ctrl-C or some other operating system action.

try:
    await asyncio.Event().wait()  # wait here until the Universe ends
finally:
    transport.close()

Upvotes: 2

Related Questions