Async function blocking discord.py heartbeat - python

I am writing a discord bot which triggers a web scraping function every 5 minutes. Even though I am running the function by calling client.loop.create_task, it still results in the following error every time:
Shard ID None heartbeat blocked for more than 10 seconds.
What can be changed to fix this error? I thought I had changed my code to call the function in a non-blocking way but it seems it still blocks.
import discord
import os
from dotenv import load_dotenv
from scrape import *
from apscheduler.schedulers.asyncio import AsyncIOScheduler
from apscheduler.triggers.cron import CronTrigger
load_dotenv()
intents = discord.Intents.default()
intents.messages = True
intents.message_content = True
# instantiate discord client
client = discord.Client(intents=intents)
async def trigger_scrape():
client.loop.create_task(scrape(client))
# discord event to check when the bot is online
#client.event
async def on_ready():
scheduler = AsyncIOScheduler(standalone=True)
scheduler.add_job(trigger_scrape, CronTrigger(minute="*/5")) # run every 5 minutes
scheduler.start()
client.run(os.getenv('TOKEN'))

Related

how do I change discord bot presence in interactions,py

I'm creating my discord bot with the interactions.py library and I've com across a problem.
I can't seem to set my bots presence:
import interactions
import os
from keep_alive import keep_alive
bot = interactions.Client(token=os.getenv('TOKEN'), command_prefix="!f")
#bot.event
async def on_start():
activity = interactions.ClientPresence(
name="zkus /mravenci",
type=0,
)
await bot.change_presence(
activity=interactions.PresenceActivityType.GAME(activity))

How to use discord.py asynchronously with another function

I am trying to run this code in a way that runs the function background() at startup while also running client.run() to start a discord bot. How can I achieve this? In its current state, depending on which order I call the functions mentioned above, it only runs the first one, so in this case it only runs the discord bot because i called the function first...
from hashlib import new
from re import I
from web3 import Web3
import sys, json, time, asyncio, threading
from logging import exception
import json
import time
import urllib3
import discord
from discord.ext.commands import Bot
from discord.ext import commands
# set rpc
web3 = Web3(Web3.HTTPProvider("rpc goes here (i have hidden for this post)"))
# use https://github.com/Cog-Creators/Red-DiscordBot/issues/581 to solve SSL problems on Mac OS
# use "token" not "client secret" for discord bot
discord_token = ('discord secret here i have hidden for this post')
# init discord stuff
client = discord.Client()
# set bot command prefix
client = commands.Bot(command_prefix = '$') #put your own prefix here
# take block data input, parse for new contract, then call discord function to broadcast
async def contractTx(txhash):
# call when new block is found to get contract addy and send it to discord
new_contract = web3.eth.get_transaction_receipt(txhash)
global contract_address
contract_address = new_contract['contractAddress']
print(f"New contract deployed: {contract_address}")
await new_contract_discord(contract_address=contract_address)
# runs on program startup
async def background():
# set block index
global block_index
block_index = web3.eth.get_block_number()
# start looping through blocks
while True:
if block_index != web3.eth.get_block_number():
# new block, do the things
# set current block to new block
block_index = web3.eth.get_block_number()
# check if transactions in new block contain new contract creation
# if yes, send to main function
print(f"NEW BLOCK: {block_index}")
global transactions
current_block = web3.eth.get_block(block_index, full_transactions=True)
transactions = current_block.transactions
for tx in transactions:
if tx['to'] != None:
# is a contract creation tx, send to export function
task1 = asyncio.create_task(contractTx(tx['hash'].hex()))
else:
# still the same block, so wait a bit
print("no new blocks")
await asyncio.sleep(1)
#client.event
async def on_ready():
print("bot online") #will print "bot online" in the console when the bot is online
#client.event
async def new_contract_discord(ctx, contract_address):
channel = client.get_channel(949889447938367531)
await channel.send(f"new contract: {contract_address}")
# test command so you know how it works
# do $foo "string" and it responds with "string"
#client.command()
async def foo(ctx, arg):
await ctx.send(arg)
# run the discord bot with the token
client.run(discord_token)
# run the background func
asyncio.run(background())```
import threading
def A():
while True:
print("A")
def B():
while True:
print("B")
threading.Thread(target=A).start()
threading.Thread(target=B).start()
This will output ABABAB... So, the functions are running simultaneously.

How do I use schedule py and Discord py together?

Main goal:
Send a message to a channel every Wednesday at 08:00
This is my current code:
import schedule
import time
import discord
import asyncio
from discord.ext import commands, tasks
from discord.ext.tasks import loop
client = discord.Client()
# IMPORTANT
channel =
botToken = ""
async def sendloop():
while True:
schedule.run_pending()
await asyncio.sleep(1)
#client.event
async def on_ready():
general_channel = client.get_channel(channel)
print('ready')
schedule.every(2).seconds.do(lambda:loop.create_task(general_channel.send('TEST')))
client.run(botToken)
So far, there are no errors, just stuck on "ready". I am a beginner using VS Code.
I wouldn't recommend using scheduler, since discord the extension task which can do the same as what you are trying to implement in your code:
from discord.ext import commands, tasks
ch = id_channel
client = commands.Bot(command_prefix='.')
TOKEN = "Token"
#every week at this time, you can change this to seconds=2
#to replicate what you have been testing
#tasks.loop(hours=168)
async def every_wednesday():
message_channel = client.get_channel(ch)
await message_channel.send("Your message")
#every_wednesday.before_loop
async def before():
await client.wait_until_ready()
every_wednesday.start()
client.run(TOKEN)
If you were to run this code on the time you want it to be repeated, it will accomplish what you want. Another approach is checking on the before() function to check if it is the right time to run if you don't want to wait and run the code on the day you want this to run.
But if you really want to use the schedule module, this post my help you: Discord.py Time Schedule

Updating the guild.members in discord.py Python

I want to create a Python Bot which tracks the time a user has spent in voice state on a server to create a ranking system. Unfortunaley i dont know how to update the guild.members list and thus the member.voice value.
I tried doing a while loop but the list didnt seem to update.
Help would be greately appreciated.
# bot.py
import os
import asyncio
import discord
import random
import datetime
from discord.utils import get
import time
from dotenv import load_dotenv
from discord.ext import tasks
load_dotenv()
TOKEN = os.getenv('DISCORD_TOKEN')
GUILD = os.getenv('DISCORD_GUILD')
client = discord.Client()
#client.event
async def on_ready():
print("Bot is ready")
while True:
time.sleep(2)
guild = discord.utils.find(lambda g: g.name == GUILD, client.guilds)
for m in guild.members:
print(m.voice)
time.sleep(2)
client.run(TOKEN)
You can use the on_voice_state_update() event to keep track of every single member that connects / disconnect from a voice channel. Make sure to use the discord.ext.commands client object.
import discord
from discord.ext import commands
client = commands.Bot(command_prefix='$')
#client.event
async def on_voice_state_update(member, before, after):
if not before.channel and after.channel:
await start_tracking(member) #your method that tracks the time
#Remember that it has to be a coroutine
if before.channel and not after.channel:
await stop_tracking(member)
edit: please do not use time.sleep() in async scripts. use asyncio for stuff like sleeping and for loops

RuntimeError: Event loop stopped before Future completed

I am trying to set up a schedule to run a subroutine. I am trying to use the subroutine example to send a message to a discord channel when the schedule is triggered. At first I attempted to try and just send the message but got an error. I then tried looking into how to solve this and have tried different ways using asyncio all of which have not worked.
If anyone is able to give me any pointers on how I could do this then it would be much appreciated.
import discord
import asyncio
import time
import schedule # pip install schedule
client = discord.Client()
#client.event
async def on_ready():
print("Connected!")
async def example(message):
await client.get_channel(CHANNEL ID).send(message)
client.run(SECRET KEY)
def scheduledEvent():
loop = asyncio.get_event_loop()
loop.run_until_complete(example("Test Message"))
loop.close()
schedule.every().minute.do(scheduledEvent)
while True:
schedule.run_pending()
time.sleep(1)
You can't run your blocking schedule code in the same thread as your asynchronous event loop (your current code won't even try to schedule tasks until the bot has already disconnected). Instead, you should use the built in tasks extension which allows you to schedule tasks.
import discord
from discord.ext import tasks, commands
CHANNEL_ID = 1234
TOKEN = 'abc'
client = discord.Client()
#client.event
async def on_ready():
print("Connected!")
#tasks.loop(minutes=1)
async def example():
await client.get_channel(CHANNEL_ID).send("Test Message")
#example.before_loop
async def before_example():
await client.wait_until_ready()
example.start()
clinet.run(TOKEN)

Categories

Resources