From 1c84659e346f7f109e3b011f9772d720c4bca9f1 Mon Sep 17 00:00:00 2001 From: Fabio Manganiello Date: Tue, 13 Oct 2020 23:25:27 +0200 Subject: [PATCH] Support for Python cronjobs in scripts folder - closes #156 --- platypush/config/__init__.py | 8 +++++++- platypush/cron/__init__.py | 31 +++++++++++++++++++++++++++++++ platypush/cron/scheduler.py | 26 +++++++++++++++++++++----- platypush/utils/__init__.py | 4 ++++ 4 files changed, 63 insertions(+), 6 deletions(-) diff --git a/platypush/config/__init__.py b/platypush/config/__init__.py index 04418a896..9b154a353 100644 --- a/platypush/config/__init__.py +++ b/platypush/config/__init__.py @@ -12,7 +12,7 @@ from typing import Optional import yaml -from platypush.utils import get_hash, is_functional_procedure, is_functional_hook +from platypush.utils import get_hash, is_functional_procedure, is_functional_hook, is_functional_cron """ Config singleton instance """ _default_config_instance = None @@ -206,6 +206,12 @@ class Config(object): if is_functional_hook(obj) }) + self.cronjobs.update(**{ + prefix + name: obj + for name, obj in inspect.getmembers(module) + if is_functional_cron(obj) + }) + def _load_scripts(self): scripts_dir = self._config['scripts_dir'] sys_path = sys.path.copy() diff --git a/platypush/cron/__init__.py b/platypush/cron/__init__.py index e69de29bb..7e92a57b9 100644 --- a/platypush/cron/__init__.py +++ b/platypush/cron/__init__.py @@ -0,0 +1,31 @@ +from functools import wraps +from logging import getLogger + +logger = getLogger(__name__) + + +def cron(cron_expression: str): + def wrapper(f): + f.cron = True + f.cron_expression = cron_expression + + @wraps(f) + def wrapped(*args, **kwargs): + from platypush import Response + + try: + ret = f(*args, **kwargs) + if isinstance(ret, Response): + return ret + + return Response(output=ret) + except Exception as e: + logger.exception(e) + return Response(errors=[str(e)]) + + return wrapped + + return wrapper + + +# vim:sw=4:ts=4:et: diff --git a/platypush/cron/scheduler.py b/platypush/cron/scheduler.py index 678eff58f..88fe24b35 100644 --- a/platypush/cron/scheduler.py +++ b/platypush/cron/scheduler.py @@ -7,6 +7,7 @@ import croniter from threading import Thread from platypush.procedure import Procedure +from platypush.utils import is_functional_cron logger = logging.getLogger('platypush:cron') @@ -25,8 +26,11 @@ class Cronjob(Thread): self.cron_expression = cron_expression self.name = name self.state = CronjobState.IDLE - self.actions = Procedure.build(name=name + '__Cron', _async=False, - requests=actions) + + if isinstance(actions, dict): + self.actions = Procedure.build(name=name + '__Cron', _async=False, requests=actions) + else: + self.actions = actions def run(self): self.state = CronjobState.WAIT @@ -36,7 +40,12 @@ class Cronjob(Thread): try: logger.info('Running cronjob {}'.format(self.name)) context = {} - response = self.actions.execute(_async=False, **context) + + if isinstance(self.actions, Procedure): + response = self.actions.execute(_async=False, **context) + else: + response = self.actions(**context) + logger.info('Response from cronjob {}: {}'.format(self.name, response)) self.state = CronjobState.DONE except Exception as e: @@ -69,8 +78,15 @@ class CronScheduler(Thread): if job and job.state not in [CronjobState.DONE, CronjobState.ERROR]: return job - self._jobs[name] = Cronjob(name=name, cron_expression=config['cron_expression'], - actions=config['actions']) + if isinstance(config, dict): + self._jobs[name] = Cronjob(name=name, cron_expression=config['cron_expression'], + actions=config['actions']) + elif is_functional_cron(config): + self._jobs[name] = Cronjob(name=name, cron_expression=config.cron_expression, + actions=config) + else: + raise AssertionError('Expected type dict or function for cron {}, got {}'.format( + name, type(config))) return self._jobs[name] diff --git a/platypush/utils/__init__.py b/platypush/utils/__init__.py index 4ef2c7314..5c1e08da4 100644 --- a/platypush/utils/__init__.py +++ b/platypush/utils/__init__.py @@ -325,6 +325,10 @@ def is_functional_hook(obj) -> bool: return callable(obj) and hasattr(obj, 'hook') +def is_functional_cron(obj) -> bool: + return callable(obj) and hasattr(obj, 'cron') and hasattr(obj, 'cron_expression') + + def run(action, *args, **kwargs): from platypush.context import get_plugin (module_name, method_name) = get_module_and_method_from_action(action)