Search code examples
pythonherokupython-requestspy-telegram-bot-api

Heroku python app (telegram bot) crashes monthly with requests exception


I have two telegram bots made with PyTelegramBotApi (not the best library, I know) deployed on Heroku. One big difference that matters: one is running with Threading to periodically send notifications to "subscribers" (around 20 people). And it crashes approximately every month with following exception trace in Heroku console:

2022-01-14T08:00:11.068553+00:00 app[worker.1]:   File "/app/.heroku/python/lib/python3.9/site-packages/telebot/apihelper.py", line 139, in _make_request
2022-01-14T08:00:11.068739+00:00 app[worker.1]:     result = _get_req_session().request(
2022-01-14T08:00:11.068748+00:00 app[worker.1]:   File "/app/.heroku/python/lib/python3.9/site-packages/requests/sessions.py", line 542, in request
2022-01-14T08:00:11.068983+00:00 app[worker.1]:     resp = self.send(prep, **send_kwargs)
2022-01-14T08:00:11.068994+00:00 app[worker.1]:   File "/app/.heroku/python/lib/python3.9/site-packages/requests/sessions.py", line 655, in send
2022-01-14T08:00:11.069233+00:00 app[worker.1]:     r = adapter.send(request, **kwargs)
2022-01-14T08:00:11.069242+00:00 app[worker.1]:   File "/app/.heroku/python/lib/python3.9/site-packages/requests/adapters.py", line 529, in send
2022-01-14T08:00:11.069448+00:00 app[worker.1]:     raise ReadTimeout(e, request=request)
2022-01-14T08:00:11.069478+00:00 app[worker.1]: requests.exceptions.ReadTimeout: HTTPSConnectionPool(host='api.telegram.org', port=443): Read timed out. (read timeout=25) 

I didn't record previous exception traces (my bad), but I can remember it looking pretty much the same (with the most recent exception being ReadTimeout). Moreover, any of my scripts were never seen in this trace (and this makes me feel it's incomplete due to some Heroku log console bug). I myself don't use requests module directly. Also it definitely can't be caused by dyno sleep as I use only worker dyno (it never sleeps). Both this bot and the one not crashing are using Heroku Postgres. Any ideas on what could be causing this exception?

EDIT: full exception trace I accidentally got in debug mode while testing somethin else on my machine:

Traceback (most recent call last):
  File "D:\Deadliner0307\lib\site-packages\urllib3\connectionpool.py", line 445, in _make_request
    six.raise_from(e, None)
  File "<string>", line 3, in raise_from
  File "D:\Deadliner0307\lib\site-packages\urllib3\connectionpool.py", line 440, in _make_request
    httplib_response = conn.getresponse()
  File "C:\Users\vva07\AppData\Local\Programs\Python\Python39-32\lib\http\client.py", line 1347, in getresponse
    response.begin()
  File "C:\Users\vva07\AppData\Local\Programs\Python\Python39-32\lib\http\client.py", line 307, in begin
    version, status, reason = self._read_status()
  File "C:\Users\vva07\AppData\Local\Programs\Python\Python39-32\lib\http\client.py", line 268, in _read_status
    line = str(self.fp.readline(_MAXLINE + 1), "iso-8859-1")
  File "C:\Users\vva07\AppData\Local\Programs\Python\Python39-32\lib\socket.py", line 704, in readinto
    return self._sock.recv_into(b)
  File "C:\Users\vva07\AppData\Local\Programs\Python\Python39-32\lib\ssl.py", line 1241, in recv_into
    return self.read(nbytes, buffer)
  File "C:\Users\vva07\AppData\Local\Programs\Python\Python39-32\lib\ssl.py", line 1099, in read
    return self._sslobj.read(len, buffer)
socket.timeout: The read operation timed out

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "D:\Deadliner0307\lib\site-packages\requests\adapters.py", line 439, in send
    resp = conn.urlopen(
  File "D:\Deadliner0307\lib\site-packages\urllib3\connectionpool.py", line 755, in urlopen
    retries = retries.increment(
  File "D:\Deadliner0307\lib\site-packages\urllib3\util\retry.py", line 532, in increment
    raise six.reraise(type(error), error, _stacktrace)
  File "D:\Deadliner0307\lib\site-packages\urllib3\packages\six.py", line 770, in reraise
    raise value
  File "D:\Deadliner0307\lib\site-packages\urllib3\connectionpool.py", line 699, in urlopen
    httplib_response = self._make_request(
  File "D:\Deadliner0307\lib\site-packages\urllib3\connectionpool.py", line 447, in _make_request
    self._raise_timeout(err=e, url=url, timeout_value=read_timeout)
  File "D:\Deadliner0307\lib\site-packages\urllib3\connectionpool.py", line 336, in _raise_timeout
    raise ReadTimeoutError(
urllib3.exceptions.ReadTimeoutError: HTTPSConnectionPool(host='api.telegram.org', port=443): Read timed out. (read timeout=25)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\vva07\OneDrive\Документы\проекты\Deadliner0307\main.py", line 450, in <module>
    bot.polling(none_stop=True, interval=1)
  File "C:\Users\vva07\OneDrive\Документы\проекты\Deadliner0307\main.py", line 446, in deadliner0307
    else:
  File "D:\Deadliner0307\lib\site-packages\telebot\__init__.py", line 633, in polling
    self.__threaded_polling(non_stop, interval, timeout, long_polling_timeout, allowed_updates)
  File "D:\Deadliner0307\lib\site-packages\telebot\__init__.py", line 692, in __threaded_polling
    raise e
  File "D:\Deadliner0307\lib\site-packages\telebot\__init__.py", line 654, in __threaded_polling
    polling_thread.raise_exceptions()
  File "D:\Deadliner0307\lib\site-packages\telebot\util.py", line 100, in raise_exceptions
    raise self.exception_info
  File "D:\Deadliner0307\lib\site-packages\telebot\util.py", line 82, in run
    task(*args, **kwargs)
  File "D:\Deadliner0307\lib\site-packages\telebot\__init__.py", line 391, in __retrieve_updates
    updates = self.get_updates(offset=(self.last_update_id + 1), 
  File "D:\Deadliner0307\lib\site-packages\telebot\__init__.py", line 371, in get_updates
    json_updates = apihelper.get_updates(self.token, offset, limit, timeout, allowed_updates, long_polling_timeout)
  File "D:\Deadliner0307\lib\site-packages\telebot\apihelper.py", line 312, in get_updates
    return _make_request(token, method_url, params=payload)
  File "D:\Deadliner0307\lib\site-packages\telebot\apihelper.py", line 139, in _make_request
    result = _get_req_session().request(
  File "D:\Deadliner0307\lib\site-packages\requests\sessions.py", line 542, in request
    resp = self.send(prep, **send_kwargs)
  File "D:\Deadliner0307\lib\site-packages\requests\sessions.py", line 655, in send
    r = adapter.send(request, **kwargs)
  File "D:\Deadliner0307\lib\site-packages\requests\adapters.py", line 529, in send
    raise ReadTimeout(e, request=request)
requests.exceptions.ReadTimeout: HTTPSConnectionPool(host='api.telegram.org', port=443): Read timed out. (read timeout=25)

Solution

  • I have found a way to at least keep the bot working. Be careful: this may not fit your application (in your case restarting straight up after a specific exception may corrupt data or break something else). In main file, I made this construction, which basically restarts a bot after an unhandled exception, which would otherwise just stop the bot:

    def exception_handler(count: int = 0):
        """Relaunching bot unless exceptions occur more than 2 times a day 
    (script is reset daily on Heroku)"""
        if count < 3:
            if count > 0:
                print("An exception occurred, relaunching . . .")
                time.sleep(5)
            try:
                deadliner0307()  # bot main function with (bot.polling starts there)
            except Exception as ex:
                count += 1
                # Notifying myself about exception via free Airbrake addon:
                notifier = pybrake.Notifier(project_id=<project_id>,
                                            project_key='<project_key>',
                                            environment='production')
                notifier.notify(ex)
                exception_handler(count)
        else:
            print("Too much exceptions occurred, shutting down . . .")
    
    if __name__ == '__main__':
        exception_handler()