""" Base Work Flow. Base Work Flow class that new {{cookiecutter.app_name}} flows should extend. Standardizes generated workflow_id and adds default on_exception method. Flows must override the decider method. """ import datetime import logging import os from garcon import activity import raven logger = logging.getLogger('garcon') class BaseFlow: """Base Garcon Workflow that other Flows can extend.""" def __init__(self, *, flow_name, version, swf_domain=None): """Initialize Flow. Args: flow_name (str): version (str): swf_domain (str): """ if swf_domain: self.domain = swf_domain else: self.domain = get_domain() self.name = flow_name self.version = version self.create = activity.create( self.domain, self.name, version=self.version, on_exception=self.on_exception) sentry_dsn = os.getenv('SENTRY_DSN') if sentry_dsn: self.sentry_client = raven.Client(dsn=sentry_dsn) else: self.sentry_client = None def on_exception(self, actor, exception): """Capture an exception that has occurred in the application. Args: actor (ActivityWorker, DeciderWorker): The actor that has received the exception. exception (Exception): The exception to capture. """ if self.sentry_client: self.sentry_client.captureException() if isinstance(actor, activity.Activity): actor.logger.error(exception, exc_info=True) else: logger.error(exception, exc_info=True) def workflow_id(self, initial_context): """Generate workflow id. Assumes a unique workflow is defined by it's context date and defaults to today's date. If that is not the case this method should be overridden. Args: initial_context (dict): The initial context for the flow. Returns: str: A unique identifier for a workflow being executed In the forms of '-YYYY-MM-DD', where YYYY-MM-DD is the context date or, if none passed the current date. """ if 'context_date' not in initial_context: date = datetime.datetime.today().strftime('%Y-%m-%d') else: date = initial_context['context_date'] return '{flow_name}-{date}'.format(flow_name=self.name, date=date) def get_domain(): """Get workflow domain. Returns: str: SWF domain the workflow should use. """ env = os.getenv('Environment') if not env or env == 'dev': domain = os.getenv('DEV_SWF_DOMAIN', 'dev') else: domain = '{}_{}'.format(env, '{{cookiecutter.app_name}}') return domain