""" Snapchat Ingestion Workflow. Ingest data from Snapchat feed. Files downloaded from sme-ca-prod-partners s3. """ import datetime from garcon.param import StaticParam from garcon_contrib.dynamo_feed_status import garcon_feed_status from snowflake_connector.etl_connector import SQLLoader from feed_ingestion.flows import base from feed_ingestion.flows.snapchat import config, tasks from feed_ingestion.flows.snapchat.stage_loader import SnapchatSL from feed_ingestion.tasks import feed_status_tasks, overall_status_tasks, \ s3_tasks sql_loader = SQLLoader(__file__) class Flow(base.FlowBase, base.FlowConfigMixin): """Class representing the workflow.""" def workflow_id(self, initial_context): """Generate workflow id. This method is overridden from FlowBase class. The only difference is using passed to workflow context 'proper_feed_type' param instead of self.name for generation workflow_id value. 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 proper_feed_type is passed by context value and YYYY-MM-DD is the context date """ if 'context_date' not in initial_context: date = datetime.datetime.today().strftime('%Y-%m-%d') else: date = initial_context['context_date'] workflow_id = '{feed_name}-{date}'.format( feed_name=self.contextified_feed_name(initial_context), date=date) return workflow_id def contextified_feed_name(self, context): """Get feed_name in context.""" return '{feed_name}-{report}'.format( feed_name=config.feed_name, report=context['report']) def __init__(self): """Initialize flow object.""" super(Flow, self).__init__(config.feed_name, version='1.0') def decider(self, schedule): """Activity decider. Args: schedule (callable): The scheduler method. """ bootstrap = schedule('bootstrap', self.bootstrap_activity) if bootstrap.result.get('bootstrap.stop') is True: return grab_drop_files = schedule( 'grab_drop_files', self.grab_drop_files_sme, requires=[bootstrap] ) if grab_drop_files.result.get('grab_drop_files.stop'): return update_feed_s3_file_status = schedule( 'update_feed_s3_file_status', self.update_feed_s3_file_status, requires=[grab_drop_files]) file_status = update_feed_s3_file_status.result.get( 'update_feed_s3_file_status.file_status') if file_status == garcon_feed_status.STATUS_NOT_AVAILABLE: return source_files = schedule( 'source_files', self.source_files, requires=[update_feed_s3_file_status]) load_staging_raw = schedule( 'load_staging_raw', self.load_staging_raw, requires=[source_files]) schedule( 'set_overall_status_ingested', self.set_status_to_ingested, requires=[load_staging_raw]) @property def bootstrap_activity(self): """First activity for the workflow.""" return self.create( name='bootstrap', tasks=base.SyncRunner( tasks.bootstrap.fill( namespace='bootstrap', date='context_date', report='report', reload='reload'))) @property def grab_drop_files_sme(self): """Grab files and upload to archive bucket on S3 for sme.""" return self.create( name='grab_drop_files_sme', tasks=base.AsyncRunner( s3_tasks.copy_file_from_sme_s3_to_theocrhard.fill( namespace='grab_drop_files_sme', secrets_path=StaticParam(config.secrets_path), source_bucket_name=StaticParam( config.s3.get('drop').get('bucket')), destination_bucket_name=StaticParam( config.s3.get('archive').get('bucket')), source_key_name='bootstrap.source_key_name', destination_key_name='bootstrap.destination_key_name', replace='bootstrap.replace_archive_files'), )) @property def update_feed_s3_file_status(self): """Update status of downloaded files.""" return self.create( name='update_feed_s3_file_status', tasks=base.SyncRunner( feed_status_tasks.update_feed_s3_file_status.fill( namespace='update_feed_s3_file_status', s3_path='bootstrap.s3_full_path', file_names='bootstrap.expected_files', feed_name='bootstrap.report_feed_name', date='bootstrap.date'))) @property def source_files(self): """Get list of source files.""" return self.create( name='source_files', tasks=base.SyncRunner( s3_tasks.source_files.fill( namespace='source_files', s3_bucket=StaticParam( config.s3.get('archive').get('bucket')), s3_path='bootstrap.archive_path', file_pattern='bootstrap.file_pattern'))) load_staging_raw = SnapchatSL.load_activity( feed_name=config.feed_name, secrets_path=config.secrets_path, sql_loader=sql_loader, requirements=dict( date='bootstrap.date', feed_name='bootstrap.report_feed_name', source_files_dict='source_files.source_files_dict', s3_dir_path='bootstrap.s3_full_path', report='report', staging_raw_table_name='bootstrap.staging_raw_table')) @property def set_status_to_ingested(self): """Set overall feed status to STATUS_INGESTED.""" return self.create( name='set_status_to_ingested', tasks=base.SyncRunner( overall_status_tasks.set_overall_status.fill( namespace='set_status_to_ingested', feed_name='bootstrap.report_feed_name', date='bootstrap.date', status=StaticParam( garcon_feed_status.STATUS_INGESTED))))