Back to Discord Py

``discord.ext.tasks`` -- asyncio.Task helpers

docs/ext/tasks/index.rst

2.7.15.3 KB
Original Source

.. _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: