async def _subscription_handler_wrapper( col_q: Any, event_name: str, callback: Callable[[m.SubscriptionResult], Awaitable[Any]]) -> None: """Wrapper for a subscription callback providing: - Basic error handling and logging - Create a task for each incoming message """ logger.debug(f"Subscription handler for {event_name} started") while True: try: event = await col_q.get() if event['type'] == 'changed': result = m.SubscriptionResult(**event['fields']) if event_name == result.eventName: callback_coro = _exception_wrapper(event_name, callback(result)) # Offload into task such that new messages can be handled directly asyncio.create_task(callback_coro) except asyncio.CancelledError: logger.debug(f"Subscription handler for {event_name} stopped") return except Exception: logger.exception( f"Exception in subscription handler for {event_name}.") sentry.exception()
def send_kafka_message(options: List[pollutil.PollOption], botname: str) -> None: try: kafkaproducer = RocketchatMensaProducer() opts = [(o.text, [u for u in o.users if u != botname]) for o in options] kafkaproducer.sendV1(opts) kafkaproducer.close() except Exception as e: logger.error(f"{type(e).__name__}: {e}", exc_info=True) sentry.exception()
async def _exception_wrapper(event_name: str, callback: Awaitable[None]) -> None: """Wrapper for coroutines to catch and log exceptions""" try: await callback except asyncio.CancelledError: logger.info(f'Subscription callback for {event_name} canceled') except Exception: sentry.exception() logger.exception(f'Caught exception in subscription callback')
async def main() -> None: masterbot = await setup_bot() while True: try: async with masterbot: logging.info(f'{c.BOTNAME} is ready') await masterbot.ddp.disconnection() # If run terminates without exception end the while true loop break except (RocketConnectionException, requests.exceptions.SSLError, JSONDecodeError): logging.error("Failed to connect. Retry in 60s") time.sleep(60) except Exception as e: logging.error(f"{type(e).__name__}: {e}", exc_info=True) sentry.exception()
async def handle(self, command: str, args: str, message: m.Message) -> None: """Handle the incoming message """ event = await self._check_running_tasks(command) try: if command == 'poll': try: await self.create_poll(args, message) except exp.RocketBotPollException as e: await self.master.ddp.send_message(message.roomid, str(e)) sentry.exception() if command == 'poll_push': match = re.match(r'\s*#(\S+)', args) if not match: await self.master.ddp.send_message( message.roomid, "Please specify a room") return room_name = match.groups()[0] if message.roomid not in self.pollmanager.polls.last_active_by_roomid: await self.master.ddp.send_message( message.roomid, "Please create a poll first") return poll = self.pollmanager.polls.last_active_by_roomid[ message.roomid] roomref = [r for r in message.channels if r.name == room_name] if len(roomref) != 0: try: await self.pollmanager.push(poll, roomref[0]._id) except exp.RocketBotPollException as e: await self.master.ddp.send_message( message.roomid, f"{e} - Am I part of that channel?") sentry.exception() return await self.master.ddp.send_message( message.roomid, "No roomref found. Is this a valid room?") finally: # Set the event will trigger the next queued handle call event.set()