"""Spike detector flow.""" from datetime import datetime from datetime import timedelta from garcon import param from garcon import runner from activity_detector.flows.base_flow import BaseFlow from activity_detector.flows.spike_detector import config from activity_detector.flows.spike_detector import tasks class Flow(BaseFlow): """Class representing the workflow.""" timeout = 1440 * 60 # 24 hours def __init__(self): """Initialize flow object.""" super(Flow, self).__init__( flow_name=config.SWF_FLOW_NAME, version=config.SWF_FLOW_VERSION) def workflow_id(self, initial_context): """Override base workflow_id. 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 we use current date - DEFAULT_SHIFT_DAYS. """ if 'context_date' not in initial_context: date = (datetime.today() - timedelta( days=config.DEFAULT_SHIFT_DAYS)).strftime('%Y-%m-%d') else: date = initial_context['context_date'] return '{flow_name}-{date}'.format(flow_name=self.name, date=date) def decider(self, schedule, context): """Activity decider. Args: schedule (callable): The scheduler method. """ bootstrap = schedule('bootstrap', self.bootstrap) check_dynamo_status = schedule( 'check_dynamo_status', self.check_dynamo_status, requires=[bootstrap]) if check_dynamo_status.result.get( 'check_dynamo_status.should_run') is False: return populate_temp_activity_history_table = schedule( 'populate_temp_activity_history_table', self.populate_temp_activity_history_table, requires=[check_dynamo_status]) populate_activity_history_table = schedule( 'populate_activity_history_table', self.populate_activity_history_table, requires=[populate_temp_activity_history_table]) drop_temp_table = schedule( 'drop_temp_table', self.drop_temp_table, requires=[populate_activity_history_table]) detect_spikes_label = schedule( 'detect_spikes_label', self.detect_spikes_label, requires=[drop_temp_table]) detect_spikes_subaccount = schedule( 'detect_spikes_subaccount', self.detect_spikes_subaccount, requires=[drop_temp_table]) schedule( 'set_dynamo_status', self.set_dynamo_status, requires=[ detect_spikes_label, detect_spikes_subaccount]) @property def bootstrap(self): """Bootstrap initial configuration.""" return self.create( name='bootstrap', tasks=runner.Sync( tasks.bootstrap.fill( namespace='bootstrap', date='context_date', label_ids='label_ids', subaccount_ids='subaccount_ids', run_id='execution.run_id'))) @property def check_dynamo_status(self): """Check dynamo status.""" return self.create( name='check_dynamo_status', tasks=runner.Sync( tasks.check_dynamo_status.fill( namespace='check_dynamo_status', date='bootstrap.target_date'))) @property def populate_temp_activity_history_table(self): """Populate temp activity history table.""" return self.create( name='populate_temp_activity_history_table', generators=[self.source_type_generator], tasks=runner.Sync( tasks.create_temp_activity_history_table.fill( namespace='populate_temp_activity_history_table', source_type='source_type', target_date='bootstrap.target_date', start_date='bootstrap.start_date', run_id='bootstrap.run_id', label_ids='bootstrap.label_ids', subaccount_ids='bootstrap.subaccount_ids'))) @property def populate_activity_history_table(self): """Populate activity history table.""" return self.create( name='populate_activity_history_table', tasks=runner.Sync( tasks.populate_activity_history_table.fill( namespace='populate_activity_history_table'))) @property def drop_temp_table(self): """Drop temp activity history table.""" return self.create( name='drop_temp_table', tasks=runner.Sync( tasks.drop_temp_table.fill( namespace='drop_temp_table'))) @property def detect_spikes_label(self): """Detect spikes at the label level.""" return self.create( name='detect_spikes_label', tasks=runner.Sync(tasks.detect_spikes.fill( namespace='detect_spikes_label', ids='bootstrap.label_ids', start_date='bootstrap.start_date', target_date='bootstrap.target_date', level=param.StaticParam('label'), run_id='bootstrap.run_id'))) @property def detect_spikes_subaccount(self): """Detect spikes at the subaccount level.""" return self.create( name='detect_spikes_subaccount', tasks=runner.Sync(tasks.detect_spikes.fill( namespace='detect_spikes_subaccount', ids='bootstrap.subaccount_ids', start_date='bootstrap.start_date', target_date='bootstrap.target_date', level=param.StaticParam('subaccount'), run_id='bootstrap.run_id'))) @property def set_dynamo_status(self): """Set activity status.""" return self.create( name='set_dynamo_status', tasks=runner.Sync( tasks.set_dynamo_status.fill( namespace='set_dynamo_status', date='bootstrap.target_date', status_label='detect_spikes_label.status', status_subaccount='detect_spikes_subaccount.status'))) def source_type_generator(self, context): """Generate parameters for populate_temp_activity_history_table. Args: context (dict): The current context. Yields: dict: Dictionary of temporary staging table names. """ for source_type in config.TYPES: yield dict(source_type=source_type)