Reputation: 262
I want my discord users to be able to queue up some tasks. In this example it is just pinging websites, but I eventually want it to do other long running tasks. When I run my bot, I get the following error:
ping-bot.py:22: RuntimeWarning: coroutine 'respond_to_channel' was never awaited
respond_to_channel()
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
Here's the code:
import os, discord, subprocess, asyncio
from discord import app_commands
from dotenv import load_dotenv
from time import sleep
from threading import Thread
load_dotenv()
TOKEN = os.getenv('DISCORD_TOKEN')
CHANNEL=os.getenv('CHANNEL_ID')
GUILD=os.getenv('GUILD_ID')
queue = []
def ping_test():
global queue
old_queue = queue.copy()
while True:
if queue != old_queue and len(queue) > 0:
old_queue = queue.copy()
retcode = subprocess.call("ping " + "-c 5 " + old_queue[0][0], shell=True)
queue.pop(0)
if len(queue) > 0:
respond_to_channel()
print(f"Now working on {queue[0][0]}")
sleep(1)
async def respond_to_channel():
ping_channel = client.get_channel(CHANNEL)
await ping_channel.send(f"Testing... Now working on {queue[0][0]}")
class MyClient(discord.Client):
def __init__(self):
super().__init__(intents=discord.Intents.default())
self.synced = False
daemon = Thread(target=ping_test, daemon=True, name='Monitor')
daemon.start()
async def on_ready(self):
print(f'Logged on as {self.user}!')
if not self.synced:
await tree.sync(guild = discord.Object(id = GUILD))
self.synced = True
client = MyClient()
tree = app_commands.CommandTree(client)
@tree.command(name = "greet", description = "Greetings!", guild = discord.Object(id = GUILD))
async def self(interaction: discord.Interaction, name: str):
await interaction.response.send_message(f"Hello {name}! I was made with Discord.py!")
print(f'Sent from {interaction.user}')
@tree.command(name = "ping-test", description = "Use my computer to ping websites", guild = discord.Object(id = GUILD))
async def self(interaction: discord.Interaction, website: str):
queue.append([website, interaction.user.id])
await interaction.response.send_message(f"Hello <@{interaction.user.id}>! You want me to ping {website}. There are currently {len(queue) - 1} jobs in front of you.", file=discord.File('test.png'))
client.run(TOKEN)
I've found some 'solutions' that do work for the ping test, but I am going to allow my discord users to use my computer for some computationally heavy tasks that can take 5+ minutes. These other solution I found break the bot if the task takes more than a few minutes.
For this reason, I decided to implement a thread that process items in a list that will tag the user in a channel when it is done.
Upvotes: 0
Views: 810
Reputation: 262
I actually wanted to use discord.ext.tasks
as it handles everything for you and runs in the async loop so nothing breaks.
I changed the thread call to
@tasks.loop(seconds = 1)
async def ping_test():
global queue
global being_worked
global client
ping_channel = client.get_channel(CHANNEL)
if len(queue) > 0:
if queue[0] != being_worked[0]:
being_worked = queue.copy()
retcode = subprocess.call("ping " + "-c 5 " + being_worked[0][0], shell=True)
queue.pop(0)
await ping_channel.send(f"Done working on {being_worked[0][0]}")
if len(queue) > 0:
await ping_channel.send(f"Testing... Now working on {queue[0][0]}")
print(f"Now working on {queue[0][0]}")
return
So now the full code looks like this:
import os, discord, subprocess
from discord import app_commands
from discord.ext import tasks
from dotenv import load_dotenv
load_dotenv()
TOKEN = os.getenv('DISCORD_TOKEN')
CHANNEL=int(os.getenv('CHANNEL_ID'))
GUILD=os.getenv('GUILD_ID')
queue = []
being_worked = []
@tasks.loop(seconds = 1)
async def ping_test():
global queue
global being_worked
global client
ping_channel = client.get_channel(CHANNEL)
if len(queue) > 0:
if queue != being_worked:
being_worked = queue.copy()
retcode = subprocess.call("ping " + "-c 15 " + being_worked[0][0], shell=True)
queue.pop(0)
await ping_channel.send(f"Done working on {being_worked[0][0]}")
if len(queue) > 0:
await ping_channel.send(f"Testing... Now working on {queue[0][0]}")
print(f"Now working on {queue[0][0]}")
return
class MyClient(discord.Client):
def __init__(self):
super().__init__(intents=discord.Intents.default())
self.synced = False
async def on_ready(self):
print(f'Logged on as {self.user}!')
if not self.synced:
await tree.sync(guild = discord.Object(id = GUILD))
self.synced = True
await ping_test.start()
client = MyClient()
tree = app_commands.CommandTree(client)
@tree.command(name = "greet", description = "Greetings!", guild = discord.Object(id = GUILD))
async def self(interaction: discord.Interaction, name: str):
await interaction.response.send_message(f"Hello {name}! I was made with Discord.py!")
print(f'Sent from {interaction.user}')
@tree.command(name = "ping-test", description = "Use my computer to ping websites", guild = discord.Object(id = GUILD))
async def self(interaction: discord.Interaction, website: str):
queue.append([website, interaction.user.id])
await interaction.response.send_message(f"Hello <@{interaction.user.id}>! You want me to ping {website}. There are currently {len(queue) - 1} jobs in front of you.", file=discord.File('test.png'))
client.run(TOKEN)
Upvotes: 1
Reputation: 106
Adding await
in front of the function respond_to_channel()
should fix the issue.
await respond_to_channel()
Upvotes: 0