1
0
mirror of https://github.com/eternnoir/pyTelegramBotAPI.git synced 2023-08-10 21:12:57 +03:00

Better error handling.

Errors now are re-raised in the Thread polling() was called from.
If none_stop is *not* set, ApiExceptions will cause the calling Thread to halt.
This commit is contained in:
pieter
2015-10-01 22:03:54 +02:00
parent 60ca1751ca
commit d14e9051d4
2 changed files with 134 additions and 58 deletions

View File

@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
import threading
import sys
from six import string_types
# Python3 queue support.
@@ -9,45 +10,97 @@ try:
except ImportError:
import queue as Queue
from apihelper import ApiException
from telebot import logger
class ThreadPool:
class WorkerThread(threading.Thread):
class WorkerThread(threading.Thread):
count = 0
def __init__(self, queue):
threading.Thread.__init__(self, name="WorkerThread{0}".format(self.__class__.count + 1))
self.__class__.count += 1
def __init__(self, exception_callback=None, queue=Queue.Queue(), name=None):
if not name:
name = "WorkerThread{0}".format(self.__class__.count + 1)
self.__class__.count += 1
threading.Thread.__init__(self, name=name)
self.queue = queue
self.daemon = True
self.received_task_event = threading.Event()
self.done_event = threading.Event()
self.exception_event = threading.Event()
self.continue_event = threading.Event()
self.exception_callback = exception_callback
self.exc_info = None
self._running = True
self.start()
def run(self):
while self._running:
self.continue_event.clear()
self.received_task_event.clear()
self.done_event.clear()
self.exception_event.clear()
try:
task, args, kwargs = self.queue.get(block=True, timeout=.01)
logger.debug("Received task")
self.received_task_event.set()
task(*args, **kwargs)
logger.debug("Task complete")
self.done_event.set()
except Queue.Empty:
pass
except ApiException as e:
logger.exception(e)
except:
logger.debug("Exception occurred")
self.exc_info = sys.exc_info()
self.exception_event.set()
if self.exception_callback:
self.exception_callback(self, self.exc_info)
self.continue_event.wait()
def put(self, task, *args, **kwargs):
self.queue.put((task, args, kwargs))
def raise_exceptions(self):
if self.exception_event.is_set():
raise self.exc_info[0], self.exc_info[1], self.exc_info[2]
def clear_exceptions(self):
self.exception_event.clear()
self.continue_event.set()
def stop(self):
self._running = False
def __init__(self, num_threads=4):
self.tasks = Queue.Queue()
self.workers = [self.WorkerThread(self.tasks) for _ in range(num_threads)]
class ThreadPool:
def __init__(self, num_threads=2):
self.tasks = Queue.Queue()
self.workers = [WorkerThread(self.on_exception, self.tasks) for _ in range(num_threads)]
self.num_threads = num_threads
self.exception_event = threading.Event()
self.exc_info = None
def put(self, func, *args, **kwargs):
self.tasks.put((func, args, kwargs))
def on_exception(self, worker_thread, exc_info):
self.exc_info = exc_info
self.exception_event.set()
worker_thread.continue_event.set()
def raise_exceptions(self):
if self.exception_event.is_set():
raise self.exc_info[0], self.exc_info[1], self.exc_info[2]
def clear_exceptions(self):
self.exception_event.clear()
def close(self):
for worker in self.workers:
worker.stop()
@@ -68,15 +121,15 @@ class AsyncTask:
def _run(self):
try:
self.result = self.target(*self.args, **self.kwargs)
except Exception as e:
self.result = e
except:
self.result = sys.exc_info()
self.done = True
def wait(self):
if not self.done:
self.thread.join()
if isinstance(self.result, Exception):
raise self.result
if isinstance(self.result, BaseException):
raise self.result[0], self.result[1], self.result[2]
else:
return self.result
@@ -130,3 +183,35 @@ def split_string(text, chars_per_string):
:return: The splitted text as a list of strings.
"""
return [text[i:i + chars_per_string] for i in range(0, len(text), chars_per_string)]
# CREDITS TO http://stackoverflow.com/questions/12317940#answer-12320352
def or_set(self):
self._set()
self.changed()
def or_clear(self):
self._clear()
self.changed()
def orify(e, changed_callback):
e._set = e.set
e._clear = e.clear
e.changed = changed_callback
e.set = lambda: or_set(e)
e.clear = lambda: or_clear(e)
def OrEvent(*events):
or_event = threading.Event()
def changed():
bools = [e.is_set() for e in events]
if any(bools):
or_event.set()
else:
or_event.clear()
for e in events:
orify(e, changed)
changed()
return or_event