"""Tasks for Ingestion Workflow.""" import datetime from garcon import task from garcon_contrib.dynamo_feed_status import garcon_feed_status from snowflake_connector.etl_connector import SQLLoader from feed_ingestion.flows.spotify_track_metrics import config from feed_ingestion.tasks import s3_tasks from feed_ingestion.util.aws import athena STOP_RESPONSE = {'stop': True} @task.decorate(timeout=700) def bootstrap(activity, date, report, reload): """Bootstrap workflow by getting the correct configurations. Args: activity (ActivityWorker): The activity worker. date (str): Reporting date (YYYY-MM-DD). report (str): one of config.reports reload (str or None): If 'True' reload status. Returns: dict: Context. """ assert report in config.reports report_config = config.reports[report] feed_name = f'{config.feed_name}_{report}' date_obj = datetime.datetime.strptime(date, '%Y-%m-%d') if reload == 'True': activity.logger.info('Delete status for feed: {} {} '.format( feed_name, date)) garcon_feed_status.delete_status(feed_name, date) elif garcon_feed_status.get_overall_status( feed_name, date) == garcon_feed_status.STATUS_INGESTED: activity.logger.info('Feed already ingested for {}'.format(date)) return { 'stop': True, 'message': '{feed_name} is already ingested for {date:%Y-%m-%d}'.format( feed_name=feed_name, date=date_obj)} activity.logger.info('Bootstrap flow for {} date: {}'.format(report, date)) archive_path = config.archive_s3_path_template.format( report=report, date=date, ) archive_bucket = config.archive_bucket s3_dir_path = f's3://{archive_bucket}/{archive_path}' return dict( feed_name=feed_name, date=date, report=report, secrets_path=config.secrets_path, archive_path=archive_path, archive_bucket=archive_bucket, s3_dir_path=s3_dir_path, staging_raw_table=report_config['staging_raw_table'], ) @task.decorate(timeout=3 * 60 * 60) def fetch_from_athena( activity, date, report, feed_name, destination_s3_bucket, destination_s3_path ): """Extract PARQUET files from SME Spotify reports. Args: activity (ActivityWorker): The activity worker. date (str): Reporting date (YYYY-MM-DD). report (str): name of report (views, creations) feed_name (str): Status name for this report in DynamoDB destination_s3_bucket (str): bucket where to put the result PARQUET destination_s3_path (str): path in destination_s3_bucket (should starts and ends with "/") """ if not destination_s3_path.endswith('/'): raise ValueError('destination_s3_path should end with /') sql_loader = SQLLoader(__file__) sql_template_name = f'athena_load_{report}' activity.logger.info(f'Loading query file {sql_template_name}') sql_template = sql_loader.load_query(sql_template_name) sql_query = sql_template.format( date=date, athena_database=config.athena_source_database, ) athena_output_location = \ f's3://{destination_s3_bucket}/{destination_s3_path}' activity.logger.info(f'Clean files in {athena_output_location}') s3_tasks.remove_files_from_path( activity=activity, path=athena_output_location, return_deleted_files=False) activity.logger.info('Running athena query...') athena.run_query( athena_query=sql_query, athena_temp_database=config.athena_temp_database, athena_workgroup=config.athena_workgroup, destination_s3_bucket=destination_s3_bucket, destination_s3_path=destination_s3_path, ) try: files = s3_tasks.source_files( activity=activity, s3_bucket=destination_s3_bucket, s3_path=destination_s3_path, file_pattern=athena.PARQUET_FILE_PATTERN ) for file in files['source_files_dict']['files']: file['found'] = True garcon_feed_status.set_overall_status( feed_name, date, garcon_feed_status.STATUS_DOWNLOADED) activity.logger.info('Done copy_from_athena_to_s3') return files except ValueError: error_message = ( f'Empty dataset. ' f'No parquet data files were found in {destination_s3_path}') activity.logger.error(error_message) garcon_feed_status.set_overall_status( feed_name, date, garcon_feed_status.STATUS_NOT_AVAILABLE) return {'stop': True, 'message': error_message}