1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
|
.. _discord_ext_tasks:
``discord.ext.tasks`` -- asyncio.Task helpers
====================================================
.. versionadded:: 1.1.0
One of the most common operations when making a bot is having a loop run in the background at a specified interval. This pattern is very common but has a lot of things you need to look out for:
- How do I handle :exc:`asyncio.CancelledError`?
- What do I do if the internet goes out?
- What is the maximum number of seconds I can sleep anyway?
The goal of this discord.py extension is to abstract all these worries away from you.
Recipes
---------
A simple background task in a :class:`~discord.ext.commands.Cog`:
.. code-block:: python3
from discord.ext import tasks, commands
class MyCog(commands.Cog):
def __init__(self):
self.index = 0
self.printer.start()
def cog_unload(self):
self.printer.cancel()
@tasks.loop(seconds=5.0)
async def printer(self):
print(self.index)
self.index += 1
Adding an exception to handle during reconnect:
.. code-block:: python3
import asyncpg
from discord.ext import tasks, commands
class MyCog(commands.Cog):
def __init__(self, bot):
self.bot = bot
self.data = []
self.batch_update.add_exception_type(asyncpg.PostgresConnectionError)
self.batch_update.start()
def cog_unload(self):
self.batch_update.cancel()
@tasks.loop(minutes=5.0)
async def batch_update(self):
async with self.bot.pool.acquire() as con:
# batch update here...
pass
Looping a certain amount of times before exiting:
.. code-block:: python3
from discord.ext import tasks
import discord
@tasks.loop(seconds=5.0, count=5)
async def slow_count():
print(slow_count.current_loop)
@slow_count.after_loop
async def after_slow_count():
print('done!')
class MyClient(discord.Client):
async def setup_hook(self):
slow_count.start()
Waiting until the bot is ready before the loop starts:
.. code-block:: python3
from discord.ext import tasks, commands
class MyCog(commands.Cog):
def __init__(self, bot):
self.index = 0
self.bot = bot
self.printer.start()
def cog_unload(self):
self.printer.cancel()
@tasks.loop(seconds=5.0)
async def printer(self):
print(self.index)
self.index += 1
@printer.before_loop
async def before_printer(self):
print('waiting...')
await self.bot.wait_until_ready()
Doing something during cancellation:
.. code-block:: python3
from discord.ext import tasks, commands
import asyncio
class MyCog(commands.Cog):
def __init__(self, bot):
self.bot = bot
self._batch = []
self.lock = asyncio.Lock()
self.bulker.start()
async def cog_unload(self):
self.bulker.cancel()
async def do_bulk(self):
# bulk insert data here
...
@tasks.loop(seconds=10.0)
async def bulker(self):
async with self.lock:
await self.do_bulk()
@bulker.after_loop
async def on_bulker_cancel(self):
if self.bulker.is_being_cancelled() and len(self._batch) != 0:
# if we're cancelled and we have some data left...
# let's insert it to our database
await self.do_bulk()
Doing something at a specific time each day:
.. code-block:: python3
import datetime
from discord.ext import commands, tasks
utc = datetime.timezone.utc
# If no tzinfo is given then UTC is assumed.
time = datetime.time(hour=8, minute=30, tzinfo=utc)
class MyCog(commands.Cog):
def __init__(self, bot):
self.bot = bot
self.my_task.start()
def cog_unload(self):
self.my_task.cancel()
@tasks.loop(time=time)
async def my_task(self):
print("My task is running!")
Doing something at multiple specific times each day:
.. code-block:: python3
import datetime
from discord.ext import commands, tasks
utc = datetime.timezone.utc
# If no tzinfo is given then UTC is assumed.
times = [
datetime.time(hour=8, tzinfo=utc),
datetime.time(hour=12, minute=30, tzinfo=utc),
datetime.time(hour=16, minute=40, second=30, tzinfo=utc)
]
class MyCog(commands.Cog):
def __init__(self, bot):
self.bot = bot
self.my_task.start()
def cog_unload(self):
self.my_task.cancel()
@tasks.loop(time=times)
async def my_task(self):
print("My task is running!")
.. _ext_tasks_api:
API Reference
---------------
.. attributetable:: discord.ext.tasks.Loop
.. autoclass:: discord.ext.tasks.Loop()
:members:
:special-members: __call__
:exclude-members: after_loop, before_loop, error
.. automethod:: Loop.after_loop()
:decorator:
.. automethod:: Loop.before_loop()
:decorator:
.. automethod:: Loop.error()
:decorator:
.. autofunction:: discord.ext.tasks.loop
:decorator:
|