Search code examples
pythonherokudiscord.pybots

How can I resolve an R12 (Exit timeout) launching with Heroku?


I am using Heroku to host a bot that I have been working on, the code itself works perfectly from when I launch it locally. However, I updated the bot yesterday adding some new functionality, and I am receiving this error code when checking the logs:

2021-08-29T13:42:44.000000+00:00 app[api]: Build succeeded
2021-08-29T13:43:05.090490+00:00 heroku[worker.1]: Error R12 (Exit timeout) -> At least one process failed to exit within 30 seconds of SIGTERM
2021-08-29T13:43:05.095578+00:00 heroku[worker.1]: Stopping remaining processes with SIGKILL
2021-08-29T13:43:05.174771+00:00 heroku[worker.1]: Process exited with status 137
2021-08-29T13:56:00.000000+00:00 app[api]: Build started by user [email protected]
2021-08-29T13:56:24.413396+00:00 app[api]: Deploy 5ff2d18b by user [email protected]
2021-08-29T13:56:24.413396+00:00 app[api]: Release v39 created by user [email protected]
2021-08-29T13:56:26.596593+00:00 heroku[worker.1]: Restarting
2021-08-29T13:56:26.610525+00:00 heroku[worker.1]: State changed from up to starting
2021-08-29T13:56:27.284912+00:00 heroku[worker.1]: Stopping all processes with SIGTERM
2021-08-29T13:56:29.770892+00:00 heroku[worker.1]: Starting process with command `python WagonCounterBot.py`
2021-08-29T13:56:30.497452+00:00 heroku[worker.1]: State changed from starting to up
2021-08-29T13:56:34.000000+00:00 app[api]: Build succeeded
2021-08-29T13:56:57.473450+00:00 heroku[worker.1]: Error R12 (Exit timeout) -> At least one process failed to exit within 30 seconds of SIGTERM
2021-08-29T13:56:57.481783+00:00 heroku[worker.1]: Stopping remaining processes with SIGKILL
2021-08-29T13:56:57.535059+00:00 heroku[worker.1]: Process exited with status 137

I think this error may be caused by the new functionality I added:

@client.listen()
async def on_message(message):
    """
    Looks for when a member calls 'bhwagon', and after 24 minutes, sends them a message
    :param message: the message sent by the user
    :return: a DM to the user letting them know their cooldown ended
    """
    channel = client.get_channel(int(WAGON_CHANNEL))  # sets the

    if message.content.startswith("bhwagon"):
        channel = message.channel
        await cool_down_ended(message)


async def cool_down_ended(message):
    """
    Sends the author of the message a personal DM 24 minutes after they type 'bhwagon' in the guild
    :param message: is the message the author sent
    :return: a message to the author
    """
    time.sleep(1440)  # sets a time for 24 minutes = 1440 seconds

    await message.author.send("Your wagon steal timer is up 🎩 time for another materials run!")

So I think I understand this error to be that Heroku doesn't allow functions to delay themselves for more than 30 seconds? Which conflicts with cool_down_ended(message) that delays for 24 minutes. Would there be any easy way around this?


Solution

    1. Don't use time.sleep in asynchronous code, it blocks entire thread. Use await asyncio.sleep(delay) instead.
    2. This is the code to handle SIGTERM from Heroku (you can add it before client.run call)
    import signal
    
    signal.signal(signal.SIGTERM, lambda *_: client.loop.create_task(client.close()))