""" TikTok Weekly Ingestion Workflow. Ingest data from TikTok Weekly feed. Files downloaded from sme s3. Files are generated for last day of a week. """ from garcon.param import StaticParam from garcon_contrib.dynamo_feed_status import garcon_feed_status from feed_ingestion.flows import base from feed_ingestion.flows.tiktok_weekly import config from feed_ingestion.flows.tiktok_weekly import tasks from feed_ingestion.tasks import load_raw_table_tasks_sf from feed_ingestion.tasks import overall_status_tasks from feed_ingestion.tasks import validate_raw_data_tasks_sf class Flow(base.FlowBase, base.FlowConfigMixin, base.FlowLoadRawMixinSF): """Class representing the workflow.""" 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, requires=[bootstrap] ) # if files unavailable, let's stop here if grab_drop_files.result.get('grab_drop_files.stop'): return # Status updated to DOWNLOADED if files are present set_status_to_downloaded = schedule( 'set_status_to_downloaded', self.set_status_to_downloaded, requires=[grab_drop_files]) create_temp_staging_raw_table = schedule( 'create_temp_staging_raw_table', self.create_temp_staging_raw_table, requires=[set_status_to_downloaded]) load_temp_staging_raw_table = schedule( 'load_temp_staging_raw_table', self.load_temp_staging_raw_table, requires=[create_temp_staging_raw_table]) load_staging_raw_table = schedule( 'load_staging_raw_table', self.load_staging_raw_table, requires=[load_temp_staging_raw_table]) schedule( 'set_status_to_ingested', self.set_status_to_ingested, requires=[load_staging_raw_table]) @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', reload='reload'))) @property def grab_drop_files(self): """Grab files and upload to archive bucket on S3.""" return self.create( name='grab_drop_files', tasks=base.SyncRunner( tasks.grab_drop_files.fill( namespace='grab_drop_files', feed_name='bootstrap.feed_name', date='bootstrap.date', drop_path='bootstrap.drop_path', archive_path='bootstrap.archive_path', platforms='platforms', filename_template='bootstrap.filename_template'))) @property def set_status_to_downloaded(self): """Set overall feed status to DOWNLOADED.""" return self.create( name='set_status_to_downloaded', tasks=base.SyncRunner( overall_status_tasks.set_overall_status.fill( namespace='set_status_to_downloaded', feed_name='bootstrap.feed_name', date='bootstrap.date', status=StaticParam( garcon_feed_status.STATUS_DOWNLOADED)))) @property def create_temp_staging_raw_table(self): """Create temp staging raw table.""" return self.create( name='create_temp_staging_raw_table', generators=[temp_staging_raw_generator], schedule_to_start=48000, tasks=base.SyncRunner( load_raw_table_tasks_sf.create_temp_staging_raw_table.fill( namespace='create_temp_staging_raw_table', date='bootstrap.date', sfdb_params='sfdb_params', feed_name='bootstrap.feed_name', secrets_path=StaticParam(config.secrets_path), temp_staging_raw_table='temp_table_name', kwargs='kwargs'))) @property def load_temp_staging_raw_table(self): """Load temp staging raw tables.""" return self.create( name='load_temp_staging_raw_table', generators=[temp_staging_raw_generator], schedule_to_start=48000, tasks=base.SyncRunner( validate_raw_data_tasks_sf.load_temp_staging_raw_table.fill( namespace='load_temp_staging_raw_table', date='bootstrap.date', sfdb_params='sfdb_params', feed_name='bootstrap.feed_name', secrets_path=StaticParam(config.secrets_path), key_dir='key_dir', temp_staging_raw_table='temp_table_name', error_limit=StaticParam(config.snowflake_error_limit), kwargs='kwargs'))) @property def load_staging_raw_table(self): """Copy the temp_staging_raw data to the feed's staging_raw tables.""" return self.create( name='load_staging_raw_table', tasks=base.SyncRunner( tasks.load_staging_raw_table.fill( namespace='load_staging_raw_table', feed_name='bootstrap.feed_name', date='bootstrap.date', downloaded_files='grab_drop_files.downloaded_files'))) @property def set_status_to_ingested(self): """Set overall feed status to to_ingested.""" return self.create( name='set_status_to_ingested', tasks=base.SyncRunner( tasks.set_status_to_ingested.fill( namespace='set_status_to_ingested', feed_name='bootstrap.feed_name', date='bootstrap.date', downloaded_files='grab_drop_files.downloaded_files', platforms='grab_drop_files.platforms'))) def temp_staging_raw_generator(context): """Generate temp_tables params needs to create & drop temp tables. Args: context (dict): the current context. Must have a 'bootstrap.temp_tables' and 'bootstrap.reports_status_names'. Yields: (dict): Dictionary for each temp table. Dictionary has a key for 'temp_table_name' & 'schema'. """ date = context['bootstrap.date'] archive_path = context['bootstrap.archive_path'] downloaded_files = context['grab_drop_files.downloaded_files'] for platform, reports in downloaded_files.items(): for report, filename in reports.items(): key_dir = f's3://{config.data_bucket}/{archive_path}{filename}' yield { 'temp_table_name': config.temp_staging_raw_table.format( platform=platform, report=report, date=date.replace('-', '')), 'key_dir': key_dir, 'kwargs': {'report': report}}