{"id":9842,"date":"2016-11-03T15:23:43","date_gmt":"2016-11-03T14:23:43","guid":{"rendered":"https:\/\/informatica.uniurb.it\/triennale\/?p=9842"},"modified":"2016-11-03T18:05:07","modified_gmt":"2016-11-03T17:05:07","slug":"quizzle-scaling-a-bot-for-the-europe-code-week","status":"publish","type":"post","link":"https:\/\/informatica.uniurb.it\/triennale-informatica\/quizzle-scaling-a-bot-for-the-europe-code-week\/","title":{"rendered":"Scaling a Bot for the Europe Code Week"},"content":{"rendered":"
A couple of days have passed since the closing of the Europe Code Week 2016<\/a>, topping the numbers of past editions with a record-breaking total of 20.000 events organized in more than 50 countries<\/a>.<\/p>\n In the context of CodeMOOC<\/a>, a massive open online course<\/strong> offered by the University of Urbino about computational thinking and coding, a large-scale coding quiz<\/strong> was planned for 20 October<\/strong>.\u00a0Using only a Telegram client and a QR Code scanner, the participants were able to take part in the game and compete with over 900 groups<\/strong> in Italy.<\/p>\n <\/p>\n Participants did register to a Telegram channel<\/a> where they would receive instructions before the start of the game.\u00a0At the start of the game, we handed out the link to a live Youtube stream<\/a>, where further instructions and quiz questions were given out.<\/p>\n For each coding quiz, the Telegram bot coordinating the event wrote a special link<\/strong> to the channel conversation, that would redirect users to the voting conversation using Telegram’s deep link<\/em> feature<\/a>.\u00a0Since each quiz had a unique identifier, the deep link<\/em> would not only transfer the user to the bot, but also send out a hidden command.<\/p>\n (Where IY4<\/em> is the hidden code for the 4th quiz question.)<\/p>\n Participants could also access the voting process by scanning a QR Code, containing the same deep link<\/em>.<\/p>\n Once invoked, the bot did ask for an answer from the user. A total of 974 participants<\/strong> (in terms of Telegram users) took part in the event. Since each person could register for a group of people (acting like a team leader), a total number of 9689 people<\/strong> were involved with the game. In other words: a lot<\/em> of messages were sent to our bot over a short amount of time.<\/p>\n Telegram supports two different modes of fetching incoming messages<\/a>: pull<\/em> and push<\/em>.<\/p>\n In pull mode, your bot server periodically connects to a Telegram end-point and downloads part of the messages queued up for delivery.\u00a0The delivery mechanism can be customized, for instance downloading a batch of messages in a single call and using long-polling<\/em> to stall the request until some data can be returned.<\/p>\n In theory, the pull method ensures higher efficiency: requests are sent out by your server, they can be controlled easily, and large batches of messages can be returned in a single HTTP data transfer.<\/p>\n However, pull operations are synchronized<\/strong> by nature. The Telegram API disallows multiple parallel requests (since, of course, the pull request operates sequentially on the delivery queue). This mode\u2014which incidentally is the only mode of operation of many other messaging platforms\u2014trades off the single, efficient data transfer step for multiple parallel message handling operations.<\/p>\n Instead of waiting for your server to fetch messages, updates are pushed to your bot’s web server to an URL of your choice (Telegram requires HTTPS, a domain name, and a certificate).\u00a0Instead of having to deal with parallelism, this mode exploits the inherent strong points of a web server<\/strong>: dealing with multiple incoming connections and handling them off efficiently to your code.<\/p>\n Based on our logs, 7.414.458 messages<\/strong> where sent to the bot through Telegram, in little over 80 minutes of operation.<\/p>\n An average of over 380\u00a0messages per minute<\/strong>\u00a0were handled, with a peak of around 1200. If you watch closely, you can get a hint of when<\/em> the 14 questions were asked.<\/p>\n Initially, our bot was configured to operate via pull and synchronous message handling, since this mode allows for far easier debugging and development.\u00a0However, as soon as the event did start, we quickly discovered that the queue of messages was growing uncontrollably and the bot simply could not keep up<\/strong>. The bot was running on a quad-core machine clocked at 2.6 GHz, with 2 GBs of RAM.<\/p>\n In conclusion, pull mode<\/strong> is perfectly suited for bot development<\/strong>, since it allows developers to control the flow of messages and to carefully debug the code.\u00a0Implementing an efficient message handling method via pull mode, however, probably isn’t worth the development effort.\u00a0As suggested<\/a>\u00a0by others, it is far easier to entrust the web server with handling parallel requests<\/strong> on your behalf.<\/p>\n
<\/a>\/start IY4<\/pre>\n
<\/a>
\nAs soon as the question was closed from our side (by simply providing the correct<\/em> answer to the bot), the bot did rank all correct answers by timestamp and signal the results on the channel<\/strong>.\u00a0The first 3 correct answers were publicly acknowledged with various, priceless, emoji medals. ?<\/p>\nMessage processing<\/h2>\n
\n14 questions<\/strong> were asked, collecting a total of 7004 responses<\/strong> by participants, over approximately one hour and a half.<\/p>\nPull mode<\/h3>\n
\nWhile transferring one single large payload and performing one single JSON decode step may be\u00a0more efficient, in pull mode you are indeed increasing the average response time<\/strong> of each message.
\nMoreover, after the download phase, data parallelism is entirely up to the developer.\u00a0Handing off message handling to different threads can be more or less easy, depending on your development framework: in Go a goroutine<\/em> can be dispatched for each message, while the same can be done for async tasks<\/em> on any .NET language.<\/p>\nPush mode<\/h3>\n
Results<\/h2>\n
<\/a>\n
\nWe quickly switched over to push mode<\/strong>. Over the course of a couple of minutes the bot was able to catch up and performed very responsively for the rest of the event.<\/p>\n