from functools import wraps import requests from flask import current_app def cronitor(task_name): def decorator(func): def ping_cronitor(command): if not current_app.config["CRONITOR_ENABLED"]: return # it's useful to have a log that a periodic task has started in case it # get stuck without generating any other logs - we know it got this far current_app.logger.info(f"Pinging Cronitor for Celery task {task_name}") task_slug = current_app.config["CRONITOR_KEYS"].get(task_name) if not task_slug: current_app.logger.error( "Cronitor enabled but task_name {} not found in environment".format( task_name ) ) return if command not in {"run", "complete", "fail"}: raise ValueError( "command {} not a valid cronitor command".format(command) ) try: resp = requests.get( "https://cronitor.link/{}/{}".format(task_slug, command), # cronitor limits msg to 1000 characters params={ "host": current_app.config["API_HOST_NAME"], }, ) resp.raise_for_status() except requests.RequestException as e: current_app.logger.warning( "Cronitor API failed for task {} due to {}".format( task_name, repr(e) ) ) @wraps(func) def inner_decorator(*args, **kwargs): ping_cronitor("run") status = "fail" try: ret = func(*args, **kwargs) status = "complete" return ret finally: ping_cronitor(status) return inner_decorator return decorator