nickoala / telepot

Python framework for Telegram Bot API
MIT License
2.43k stars 474 forks source link

SSL Error when multiprocessing #314

Closed Scratchcat1 closed 7 years ago

Scratchcat1 commented 7 years ago

It seems that if two processes log on using the same bot token after a short period one will crash with an SSL error. Steps to reproduce: Launching two instance of the python interpreter or two processes via multiprocessing and then creating two bot objects which then check for issues causes the one process to crash. This may not be instantanious , however sending a message to the bots which then send a response back to the chat causes one of the bots to crash with an SSL Error. Passing a bot object to another process causes the same issue. If the second bot doesn't send a message the error does not occur.

Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/urllib3/connectionpool.py", line 331, in _make_request
    httplib_response = conn.getresponse(buffering=True)
TypeError: getresponse() got an unexpected keyword argument 'buffering'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/urllib3/connectionpool.py", line 516, in urlopen
    body=body, headers=headers)
  File "/usr/lib/python3/dist-packages/urllib3/connectionpool.py", line 333, in _make_request
    httplib_response = conn.getresponse()
  File "/usr/lib/python3.4/http/client.py", line 1172, in getresponse
    response.begin()
  File "/usr/lib/python3.4/http/client.py", line 351, in begin
    version, status, reason = self._read_status()
  File "/usr/lib/python3.4/http/client.py", line 313, in _read_status
    line = str(self.fp.readline(_MAXLINE + 1), "iso-8859-1")
  File "/usr/lib/python3.4/socket.py", line 371, in readinto
    return self._sock.recv_into(b)
  File "/usr/lib/python3.4/ssl.py", line 745, in recv_into
    return self.read(nbytes, buffer)
  File "/usr/lib/python3.4/ssl.py", line 617, in read
    v = self._sslobj.read(len, buffer)
ssl.SSLError: [SSL: DECRYPTION_FAILED_OR_BAD_RECORD_MAC] decryption failed or bad record mac (_ssl.c:1769)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/media/pi/USB2/Year 12/Computing/HedaBot.py", line 51, in mainLoop
    update = self.bot.getUpdates(self.update_id + 1)
  File "/usr/local/lib/python3.4/dist-packages/telepot/__init__.py", line 876, in getUpdates
    return self._api_request('getUpdates', _rectify(p))
  File "/usr/local/lib/python3.4/dist-packages/telepot/__init__.py", line 434, in _api_request
    return api.request((self._token, method, params, files), **kwargs)
  File "/usr/local/lib/python3.4/dist-packages/telepot/api.py", line 130, in request
    r = fn(*args, **kwargs)  # `fn` must be thread-safe
  File "/usr/lib/python3/dist-packages/urllib3/request.py", line 135, in request_encode_body
    **urlopen_kw)
  File "/usr/lib/python3/dist-packages/urllib3/poolmanager.py", line 153, in urlopen
    response = conn.urlopen(method, u.request_uri, **kw)
  File "/usr/lib/python3/dist-packages/urllib3/connectionpool.py", line 543, in urlopen
    raise SSLError(e)
urllib3.exceptions.SSLError: [SSL: DECRYPTION_FAILED_OR_BAD_RECORD_MAC] decryption failed or bad record mac (_ssl.c:1769)
nickoala commented 7 years ago

Telegram does not allow simultaneous getUpdates of the same token by two processes. So I guess your situation is "expected" :smile:

Scratchcat1 commented 7 years ago

I see, that would explain it Thanks

milutinke-kortechs commented 6 years ago

@nickoala Hi. I can't find anything that solves this problem. I have the same problem with Django, PostgresSQL Database.

How can I use multiprocessing and avoid this error? Thanks

Scratchcat1 commented 6 years ago

@milutinke-kortechs The way I solved it was to create another thread/process dedicated to interacting with send/recv. Messages would be forwarded on to other workers and messages to be sent would be put back on an output queue for the bot thread to send.

Just create the send/recv worker on a different thread and connect it to the rest of the application using two queues (Input and output). If you need to send a response to a particular part of the program you may need to setup some sort of routing with multiple queues.

ongyiren commented 5 years ago

@Scratchcat1 Hi, i am facing the same issue at the moment. May i know how you create a send and receive worker? Thank you!

Scratchcat1 commented 5 years ago

@ongyiren

I created a dedicated thread with two queues, outbox and inbox. The thread simply keeps checking if messages have been sent to the bot and puts any it finds into the inbox queue to be processed by the rest of the application. It then sends any messages in the outbox queue (placed there by other threads).

I would recommend using dedicated queues for each consumer thread if you have multiple and mapping each chat to a specific inbox queue so that any conversation will be processed in the right order.