More annotations and add warning.

This commit is contained in:
Alex Root Junior 2017-08-23 22:23:57 +03:00
parent 0b21996b87
commit 6696c8e9ad
3 changed files with 54 additions and 7 deletions

View file

@ -715,6 +715,21 @@ class Dispatcher:
return FSMContext(storage=self.storage, chat=chat, user=user) return FSMContext(storage=self.storage, chat=chat, user=user)
def async_task(self, func): def async_task(self, func):
"""
Execute handler as task and return None.
Use that decorator for slow handlers (with timeouts)
.. code-block:: python3
@dp.message_handler(commands=['command'])
@dp.async_task
async def cmd_with_timeout(message: types.Message):
await asyncio.sleep(120)
return SendMessage(message.chat.id, 'KABOOM').reply(message)
:param func:
:return:
"""
def process_response(task): def process_response(task):
response = task.result() response = task.result()
self.loop.create_task(response.execute_response(self.bot)) self.loop.create_task(response.execute_response(self.bot))

View file

@ -2,7 +2,6 @@ import asyncio
import asyncio.tasks import asyncio.tasks
import datetime import datetime
import functools import functools
import time
import typing import typing
from typing import Union, Dict, Optional from typing import Union, Dict, Optional
@ -12,6 +11,8 @@ from .. import types
from ..bot import api from ..bot import api
from ..bot.base import Integer, String, Boolean, Float from ..bot.base import Integer, String, Boolean, Float
from ..utils import json from ..utils import json
from ..utils.deprecated import warn_deprecated as warn
from ..utils.exceptions import TimeoutWarning
from ..utils.payload import prepare_arg from ..utils.payload import prepare_arg
DEFAULT_WEB_PATH = '/webhook' DEFAULT_WEB_PATH = '/webhook'
@ -41,10 +42,6 @@ class WebhookRequestHandler(web.View):
""" """
def __init__(self, request):
self._start_time = time.time()
super(WebhookRequestHandler, self).__init__(request)
def get_dispatcher(self): def get_dispatcher(self):
""" """
Get Dispatcher instance from environment Get Dispatcher instance from environment
@ -85,9 +82,19 @@ class WebhookRequestHandler(web.View):
return web.Response(text='ok') return web.Response(text='ok')
async def process_update(self, update): async def process_update(self, update):
"""
Need respond in less than 60 seconds in to webhook.
So... If you respond greater than 55 seconds webhook automatically respond 'ok'
and execute callback response via simple HTTP request.
:param update:
:return:
"""
dispatcher = self.get_dispatcher() dispatcher = self.get_dispatcher()
loop = dispatcher.loop loop = dispatcher.loop
# Analog of `asyncio.wait_for` but without cancelling task
waiter = loop.create_future() waiter = loop.create_future()
timeout_handle = loop.call_later(RESPONSE_TIMEOUT, asyncio.tasks._release_waiter, waiter) timeout_handle = loop.call_later(RESPONSE_TIMEOUT, asyncio.tasks._release_waiter, waiter)
cb = functools.partial(asyncio.tasks._release_waiter, waiter) cb = functools.partial(asyncio.tasks._release_waiter, waiter)
@ -107,11 +114,22 @@ class WebhookRequestHandler(web.View):
return fut.result() return fut.result()
else: else:
fut.remove_done_callback(cb) fut.remove_done_callback(cb)
fut.add_done_callback(self.response_task) fut.add_done_callback(self.respond_via_request)
finally: finally:
timeout_handle.cancel() timeout_handle.cancel()
def response_task(self, task): def respond_via_request(self, task):
"""
Handle response after 55 second.
:param task:
:return:
"""
warn(f"Detected slow response into webhook. "
f"(Greater than {RESPONSE_TIMEOUT} seconds)\n"
f"Recommended to use 'async_task' decorator from Dispatcher for handler with long timeouts.",
TimeoutWarning)
dispatcher = self.get_dispatcher() dispatcher = self.get_dispatcher()
loop = dispatcher.loop loop = dispatcher.loop
@ -121,6 +139,12 @@ class WebhookRequestHandler(web.View):
asyncio.ensure_future(response.execute_response(self.get_dispatcher().bot), loop=loop) asyncio.ensure_future(response.execute_response(self.get_dispatcher().bot), loop=loop)
def get_response(self, results): def get_response(self, results):
"""
Get response object from results.
:param results: list
:return:
"""
if results is None: if results is None:
return None return None
for result in results: for result in results:

View file

@ -13,6 +13,14 @@ class TelegramAPIError(Exception):
super(TelegramAPIError, self).__init__(_clean_message(message)) super(TelegramAPIError, self).__init__(_clean_message(message))
class AIOGramWarning(Warning):
pass
class TimeoutWarning(AIOGramWarning):
pass
class ValidationError(TelegramAPIError): class ValidationError(TelegramAPIError):
pass pass