Skip to content

Commit dd232c6

Browse files
committed
Add post
1 parent 42195c5 commit dd232c6

File tree

2 files changed

+47
-1
lines changed

2 files changed

+47
-1
lines changed

_posts/2016-08-28-telegram-bot-voice-messages.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ title: "Voice messages with python-telegram-bot"
44
date: 2016-08-28 11:10:00 +0200
55
categories: telegram python
66
---
7-
Recently I was playing around with the Telegram's Bot API using the [python-telegram-bot](https://github.com/python-telegram-bot/python-telegram-bot) library. I have faced a small but curious issue. Let's say that we want to sent an mp3 file to a Telegram chat. We have two options here: either send the file as a voice message or as a general file. In the first case the audio should be playable right through any Telegram client, while in the second case a user should be able to download it. With python-telegram-bot this can be done via methods Bot.sendVoice and Bot.sendDocument.
7+
Recently I was playing around with the Telegram's Bot API using the [python-telegram-bot](https://github.com/python-telegram-bot/python-telegram-bot) library. I have faced a small but curious issue. Let's say that we want to send an mp3 file to a Telegram chat. We have two options here: either send the file as a voice message or as a general file. In the first case the audio should be playable right through any Telegram client, while in the second case a user should be able to download it. With python-telegram-bot this can be done via methods Bot.sendVoice and Bot.sendDocument.
88

99
By the way, for the web client both options seem to be equal at a first sight: a user has *Download* and *Play* links in either case. However, when we send an audio as a voice message, it gets wrapped in the mpeg container, and that is what our user downloads.
1010

@@ -153,3 +153,5 @@ song_filename = somehow_extract_name_from_url(song_url)
153153
voice = BufferWithName(song_response.content, song_filename)
154154
bot.sendVoice(chat_id, voice=voice)
155155
{% endhighlight %}
156+
157+
Another option would be to wrap BytesIO in io.BufferedReader which has *name* attribute.
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
---
2+
layout: post
3+
title: "SSL problem in multiprocess uWSGI app"
4+
date: 2016-09-04 17:31:00 +0200
5+
categories: uwsgi
6+
---
7+
I have encountered a tricky issue while playing with [python-telegram-bot](https://github.com/python-telegram-bot/python-telegram-bot) library. A clear sign of the issue is the following exception appearing from time to time when we send a message to Telegram via python-telegram-bot:
8+
9+
{% highlight Bash %}
10+
urllib3 HTTPError [Errno 1] _ssl.c:1429: error:1408F119:SSL routines:SSL3_GET_RECORD:decryption failed or bad record mac
11+
{% endhighlight %}
12+
13+
Well, actually the issue has nothing to do with python-telegram-bot library itself, but is rather related to the implementation of OpenSSL in Debian. The problem appears when *the same* SSL connection is used in two concurrent processes. As always with concurrency-related issues, everything might work correctly for a while, then break suddenly and mysteriously, and then continue to work for another hundreds of trials. Leaving the deep internals of SSl aside, let's see how it affects a telegram bot.
14+
15+
<!--more-->
16+
17+
Commonly uWSGI is configured to spawn multiple working processes to serve requests. Every process runs its own instance of our Flask application. What causes the problem is the way uWSGI spawns these processes by default. It initializes an application only once and then copies it to several working processes. This saves some memory, but unfortunately is not appropriate in our case. Most likely in our bot application we create telegram.Bot object only once - on initialization - and end up with the same instance in all the processes. Shared telegram.Bot object means shared SSL connection.
18+
19+
In order to change the default behavior we should set *lazy-apps* option in uWSGI config. Note that there is another option called *lazy*, but its usage is strongly discouraged in the [doc](http://uwsgi-docs.readthedocs.io/en/latest/ThingsToKnow.html).
20+
21+
To sum it up, the uWSGI config *your-app-name.ini* might look somewhat like this:
22+
23+
{% highlight Bash %}
24+
[uwsgi]
25+
module = <FILE:CALLABLE>
26+
27+
master = true
28+
processes = 2
29+
30+
socket = <SOCKET>
31+
chmod-socket = 666
32+
vacuum = true
33+
34+
# Fix 'ssl+multiprocessing' issue
35+
lazy-apps = true
36+
37+
die-on-term = true
38+
{% endhighlight %}
39+
40+
### Relevant references:
41+
* [Issue in "requests" lib's tracker](https://github.com/kennethreitz/requests/issues/1906)
42+
* [Stackoverflow](http://stackoverflow.com/questions/3724900/python-ssl-problem-with-multiprocessing)
43+
* [Stackoverflow](http://stackoverflow.com/questions/22752521/uwsgi-flask-sqlalchemy-and-postgres-ssl-error-decryption-failed-or-bad-reco)
44+

0 commit comments

Comments
 (0)