How to correctly implement async/await in a Discord bot with Python

I’m facing difficulties while developing my Discord bot, particularly with async functions. I created a command to initiate a monitoring task, but whenever I attempt to invoke another async function, I receive a warning stating that the coroutine was never awaited.

Here’s the code I have:

@bot.command(name='start_monitor')
async def initiate_monitoring(ctx, ip_address):
    active_ips.append(ip_address)
    await ctx.send(f'Monitoring is now active for: {ip_address}')
    print(f'Active IPs: {active_ips}')
    if len(active_ips) == 1:
        monitor_ip_status()  # This is where I encounter the warning
        print('Beginning monitoring procedure.')

async def monitor_ip_status():
    global previous_response
    global is_monitoring
    for ip in active_ips:
        if is_monitoring:
            while True:
                stop_loop = False
                response_data = requests.get(api_url.format(ip)).json()
                info_message = f"IP Status:\nStarted at: {response_data['start_time']}\nLoad: {response_data['load']}%\nUp Time: {response_data['up_time']} hours"
                current_response = response_data.get('load')
                if current_response == previous_response:
                    print('No updates in status.')
                    time.sleep(10)
                else:
                    previous_response = current_response
                    print('Status update available, sending message!')
                    try:
                        bot.send_message(info_message)
                    except Exception:
                        bot.send_message("Monitoring has ended!")
                        if len(active_ips) == 0:
                            stop_loop = True
                        active_ips.remove(ip)
                time.sleep(10)
                if stop_loop:
                    break

I’ve attempted to use await but it doesn’t seem to fit well. I also examined how to create tasks with the event loop, but I’m confused about the difference between coroutines and futures. Can someone explain the proper way to call an async function from another async function in this situation?

the issue is you’re calling monitor_ip_status() without await. change it to await monitor_ip_status() or better yet use asyncio.create_task(monitor_ip_status()) to run it in backgroud without blocking your command response.

Your coroutine warning occurs because you’re calling an async function synchronously. The fundamental issue is mixing blocking and non-blocking operations in your event loop. Instead of directly calling monitor_ip_status(), wrap it with bot.loop.create_task(monitor_ip_status()) to run it concurrently. This prevents blocking your command execution while allowing the monitoring to continue in the background. Additionally, your monitoring function has several problems that will cause runtime errors. The time.sleep() calls will freeze your entire bot - replace them with await asyncio.sleep(10). Your bot.send_message() method doesn’t exist in discord.py; you need to store the channel from your command context and use await channel.send(message) instead. Consider using asyncio.gather() or asyncio.TaskGroup() if you need to manage multiple monitoring tasks simultaneously. This approach gives you better control over task lifecycle and error handling.

Looking at your code, the main problem is that you’re calling an async function without properly handling it. When you call monitor_ip_status() without await, Python creates a coroutine object but never actually executes it, hence the warning.

However, using await monitor_ip_status() would block your command from responding until the monitoring loop finishes, which is not what you want. The solution is to create a background task using asyncio.create_task() as mentioned, but there are other issues in your monitoring function.

You’re using time.sleep() which blocks the entire event loop. Replace it with await asyncio.sleep(10) instead. Also, bot.send_message() doesn’t exist in discord.py - you need to pass the channel object and use await channel.send(). You’ll need to store the channel reference from your command context to use it later in the monitoring function.

The requests library is also blocking - consider using aiohttp for async HTTP requests to keep everything non-blocking.