from asyncio import all_tasks, CancelledError, create_task, current_task, get_running_loop, run from loguru import logger from signal import SIGINT, SIGTERM from typing import Any, Callable from ctp_slack_bot.containers import Container from ctp_slack_bot.core.logging import setup_logging async def handle_shutdown_signal() -> None: logger.info("Received shutdown signal.") for task in all_tasks(): if task is not current_task() and not task.done(): task.cancel() logger.trace("Cancelled task {}.", task.get_name()) logger.info("Cancelled all tasks.") def create_shutdown_signal_handler() -> Callable[[], None]: def shutdown_signal_handler() -> None: create_task(handle_shutdown_signal()) return shutdown_signal_handler async def main() -> None: # Setup logging. setup_logging() logger.info("Starting application…") # Set up dependency injection container. container = Container() container.wire(packages=['ctp_slack_bot']) # Kick off services which should be active from the start. container.content_ingestion_service() container.question_dispatch_service() container.schedule_service() # Start the Slack socket mode handler in the background. socket_mode_handler = await container.socket_mode_handler() slack_bolt_task = create_task(socket_mode_handler.start_async()) shutdown_signal_handler = create_shutdown_signal_handler() loop = get_running_loop() loop.add_signal_handler(SIGINT, shutdown_signal_handler) loop.add_signal_handler(SIGTERM, shutdown_signal_handler) try: logger.info("Starting Slack Socket Mode handler…") await slack_bolt_task except CancelledError: logger.info("Shutting down application…") finally: await socket_mode_handler.close_async() await container.shutdown_resources() if __name__ == "__main__": run(main())