import logging import os from concurrent.futures import ThreadPoolExecutor from datetime import datetime import time from ssavva.amazon_unlimited.backfilling import config, consts from ssavva.amazon_unlimited.backfilling import dynamodb_utils from ssavva.amazon_unlimited.backfilling import swf_utils from ssavva.amazon_unlimited.backfilling import jenkins_utils _thread_pool_executor = ThreadPoolExecutor(max_workers=10) logger = logging.getLogger(__name__) def configure_logging(log_name): """Configure logging in the project. Args: etl_name (str): Name of the started ETL. """ cli_dir = os.path.dirname(os.path.abspath(__file__)) if not os.path.exists(config.logs_directory): os.makedirs(os.path.join(cli_dir, config.logs_directory)) start_datetime = datetime.now().strftime('%Y-%m-%dT%H:%M:%S') log_file_name = '{name}_{datetime}.log'.format( name=log_name, datetime=start_datetime) log_file_path = os.path.join(cli_dir, config.logs_directory, log_file_name) logging.basicConfig( format=config.logging_format, handlers=[ logging.FileHandler(log_file_path), logging.StreamHandler() ], level=logging.INFO) def _get_ingestion_tasks(): dates_for_ingestion = dynamodb_utils.get_all_items_except_status( config.INGESTION_TABLE, consts.WorkflowStatus.INGESTED) clean_dates = [e['date']['S'] for e in dates_for_ingestion] return sorted(clean_dates) def _get_skip(required_date): return (datetime.now() - datetime.strptime(required_date, '%Y-%m-%d')).days def _get_ingestion_context(date): check_date = datetime.strptime(date, '%Y-%m-%d') if check_date < datetime.strptime('2018-05-01', '%Y-%m-%d'): return '{"countries": "IT, ES, GB, US, FR", "reload": "True"}' else: return '{"countries": "IT, ES, GB, US, FR, DE, AU, AT", "reload": "True"}' def run_ingestion_task(date): skip = _get_skip(date) context = _get_ingestion_context(date) jenkins_utils.build_job_and_wait_the_end( config.JENKINS_INGESTION_JOB, { 'SKIP': skip, 'DAYS': 1, 'CONTEXT': context } ) dynamodb_utils.update_item( config.INGESTION_TABLE, 'date', date, consts.status_column, consts.WorkflowStatus.STARTED) def run_aggregation_task(date): logger.info('Running aggregation for {}'.format(date)) jenkins_utils.build_job_and_wait_the_end( config.JENKINS_AGGREGATION_JOB, { 'context_date_range': '{}_{}'.format(date, date), 'reload': True } ) dynamodb_utils.update_item( config.AGGREGATION_TABLE, 'date', date, consts.status_column, consts.WorkflowStatus.STARTED) def monitor_ingestion_run(date): try: logger.info('Start monitoring in SWF for {}'.format(date)) workflow_id = config.INGESTION_WORKFLOW_ID_TEMPLATE.format(date=date) execution_result = swf_utils.wait_workflow_execution( config.SWF_INGESTION_DOMAIN, config.SWF_INGESTION_WORKFLOW, workflow_id) if execution_result: logger.info('SWF ingestion execution finished successfully for {}'.format(date)) dynamodb_utils.update_item( config.INGESTION_TABLE, 'date', date, consts.status_column, consts.WorkflowStatus.INGESTED) run_aggregation_task(date) else: logger.warning('SWF ingestion executeion has failed for {}'.format(date)) dynamodb_utils.update_item( config.INGESTION_TABLE, 'date', date, consts.status_column, consts.WorkflowStatus.FAILED) except Exception as e: logger.critical('Something went wrong! date {}.\n Exception: {}'. format(date, e)) def backfill(): dates_for_ingestion = _get_ingestion_tasks() for date in dates_for_ingestion: logger.info('Starting process new date {}'.format(date)) while True: if swf_utils.can_run_flow( config.SWF_INGESTION_DOMAIN, config.SWF_INGESTION_WORKFLOW): logger.info('Can run in SWF {} ingestion'.format(date)) run_ingestion_task(date) logger.info('Run in SWF {} ingestion'.format(date)) _thread_pool_executor.submit(monitor_ingestion_run, date) break else: logger.info('Waiting for SWF availability...') time.sleep(60) if __name__ == '__main__': backfill()