Ejemplo n.º 1
0
def email_callback(**kwargs):

    email_template = f"""

    From {kwargs['yesterday_ds']}to {kwargs['ds']}, the number of trips observed was { kwargs['ti'].xcom_pull(key='xcom_trips', task_ids='computing_stats') } across {kwargs['ti'].xcom_pull(key='xcom_devices', task_ids='computing_stats')} devices. 

    Company Trips Table: 

    { kwargs['ti'].xcom_pull(key='trips_table', task_ids='computing_stats') }

    Company Devices Table: 

    { kwargs['ti'].xcom_pull(key='device_table', task_ids='computing_stats') } <br> 

    Status Table <br> 
    { kwargs['ti'].xcom_pull(key='sum_table', task_ids='computing_stats')}

    """
    send_email(to=[
        '*****@*****.**',
        '*****@*****.**',
        '*****@*****.**',
        '*****@*****.**',
        '*****@*****.**',
        '*****@*****.**',
        '*****@*****.**',
        '*****@*****.**',
        '*****@*****.**',
        '*****@*****.**',
    ],
               subject=f"Dockless Stats for { kwargs['yesterday_ds'] }",
               html_content=email_template)

    return True
Ejemplo n.º 2
0
def notify_email_failure(contextDict, **kwargs):
    """
    Send custom email alerts.
    
    Params:
		contextDict	: context dictionery from airflow
		**kwargs	: kwargs for extra params.
  
    """
    if 'file' in (contextDict['params']):
        files = (contextDict['params']['file'])
    else:
        files = []
    files.append(get_log_location(contextDict))
    email_list = (contextDict['params']['email_list'])

    # email title.
    title = "{} DA: {} {}".format(CLIENT, contextDict['task'].task_id,
                                  failure_title)

    # email contents
    body = "{}<br>{}<br><br>{}<br><br>{}".format(
        salutation, failure_body, contextDict['params']['task_failure_msg'],
        regards)

    files = [f for f in files if os.path.exists(f)]
    if len(files) == 0:
        send_email(email_list, title, body)
    else:
        send_email(email_list, title, body, files)
def sendemail(to_addr_list, cc_addr_list, subject, message, **kwargs):
    # xcom_pull alert from last task's return value
    task_instance = kwargs["task_instance"]
    cd_alert = task_instance.xcom_pull(task_ids="detect_outliers")

    # if no outliers found, skip sending email
    if bool(cd_alert):
        # prepare email body
        for cd, alert in cd_alert.items():
            logging.info(alert)

            files = []
            for key, value in alert.items():
                files.append(prefix + value[1])

            html_content = make_html_content(cd, alert, message)
            send_email(
                to_addr_list[cd],
                subject,
                html_content,
                files=files,
                cc=cc_addr_list[cd],
            )
        return "Outliers founded. Alert Email sent. Success!"

    return "No alert generated. Email not sent."
Ejemplo n.º 4
0
def airflow_email_report(
    contact_email: str, org_name: str, email_metadata_xcom_args, ti, **kwargs
):
    """Send email indicating that data has been uploaded.

    Includes number of rows uploaded, and info about dropped rows and values.
    """
    subject_header = "[UPLOAD COMPLETE] {} Report for Mission Impact upload on {}".format(
        org_name, kwargs["execution_date"].strftime("%m/%d/%y")
    )

    dropped_data = ti.xcom_pull(**email_metadata_xcom_args)
    num_rows_uploaded = dropped_data[data_processor.NUM_ROWS_TO_UPLOAD_KEY]
    dropped_rows = dropped_data[data_processor.DROPPED_ROWS_KEY]
    dropped_vals = dropped_data[data_processor.DROPPED_VALUES_KEY]

    message = format_successful_upload(num_rows_uploaded, dropped_rows, dropped_vals)

    email_content = HEADER + message
    log_email(contact_email, email_content)

    if contact_email:
        send_email(
            contact_email,
            subject_header,
            email_content,
            mime_subtype="mixed",
            mime_charset="utf8",
        )
Ejemplo n.º 5
0
def notify_success_email(contextDict, **kwargs):
    """Send custom email alerts."""

    dag_id = contextDict['dag'].dag_id
    task_id = contextDict['task'].task_id
    if 'msg' in kwargs:
        msg = kwargs['msg']
    else:
        msg = "The {} job succeeded for {}.".format(
            dag_id, contextDict['yesterday_ds'])

    # email title.
    title = "Airflow alert: {} succeeded".format(dag_id)

    # email contents
    body = """
    Hi Everyone, <br>
    <br>
    {}<br>
    <br>
    Forever yours,<br>
    Airflow bot <br>
    """.format(msg)

    send_email(['*****@*****.**', '*****@*****.**'], title, body)
Ejemplo n.º 6
0
def airflow_email_column_mapping_validation_failure(
    contact_email: str,
    org_name: str,
    email_metadata_xcom_args: str,
    column_mapping_sheet_id: str,
    ti,
    **kwargs,
):
    subject_header = "[ACTION REQUIRED] {} Failed column mapping validation for GDI Pipeline ({})".format(
        org_name, kwargs["execution_date"].strftime("%m/%d/%y")
    )

    message = f"""Your column mappings for the GDI pipeline are invalid. Please fix this issue at:
     https://docs.google.com/spreadsheets/d/{column_mapping_sheet_id}
    <br>Note that no data will be uploaded to Gateway until this issue is fixed. Details below:<br>"""

    message += format_validation_failures(ti.xcom_pull(**email_metadata_xcom_args))

    message += "<br>Be aware that column mappings are case sensitive."

    email_content = HEADER + message
    log_email(contact_email, email_content)

    if contact_email:
        send_email(
            contact_email,
            subject_header,
            email_content,
            mime_subtype="mixed",
            mime_charset="utf8",
        )
Ejemplo n.º 7
0
 def execute(self, context):
     send_email(self.to,
                self.subject,
                self.html_content,
                files=self.files,
                cc=self.cc,
                bcc=self.bcc)
Ejemplo n.º 8
0
def email_failures(task_instance, ds, **kwargs):
    status = task_instance.xcom_pull(task_ids="download_data")
    error_agencies = status["errors"]

    html_report = pd.DataFrame(error_agencies).to_html(border=False)

    html_content = f"""\
The following agency GTFS feeds could not be extracted on {ds}:

{html_report}
"""

    send_email(
        to=[
            "*****@*****.**",
            "*****@*****.**",
            "*****@*****.**",
            "*****@*****.**",
            "*****@*****.**",
        ],
        html_content=html_content,
        subject=
        (f"Operator GTFS Errors for {datetime.datetime.now().strftime('%Y-%m-%d')}"
         ),
    )
Ejemplo n.º 9
0
def on_failure_email(dag_id, task_id, message):
    """
    This function is used to send an email to the registered email id
    in the configuration variable 'config'
    :param dag_id: str, name of the dag
    :param task_id: str, name of the task which failed
    :param message: str, exception trace that lead to the failure
    :return: None
    """

    # check for empty
    if is_empty(dag_id) or is_empty(task_id) or is_empty(message):
        raise InvalidArguments("dag_id, task_id and message can't be empty")

    # check for none
    if dag_id is None or task_id is None:
        raise InvalidArguments("dag_id, task_id and message can't be None")

    message = '<img src="https://airflow.apache.org/images/feature-image.png" width="400" height="100"/>' \
              '<h2>AIRFLOW TASK FAILURE:</h2><hr/>' \
              '<strong>DAG : </strong>    {} <br/><hr/>' \
              '<strong>TASKS:</strong>  {}<br/><hr/>' \
              '<strong>Reason:</strong> {}<br/><hr/>' \
        .format(dag_id, task_id, message)

    try:
        config = json.loads(Variable.get("config"))
        email = config['email']
    except NameError as e:
        raise ConfigVariableNotFoundException()

    send_email(to=email, subject='Airflow Notification', html_content=message)
Ejemplo n.º 10
0
def airflow_email_field_mapping_validation_failure(
    contact_email: str,
    org_name: str,
    email_metadata_xcom_args: str,
    field_mapping_sheet_id: str,
    ti,
    **kwargs,
):
    subject_header = "[ACTION REQUIRED] {} Failed field mapping validation for GDI Pipeline ({})".format(
        org_name, kwargs["execution_date"].strftime("%m/%d/%y")
    )

    message = f"""Your field mappings for the GDI pipeline are invalid. Please fix this issue at:
     https://docs.google.com/spreadsheets/d/{field_mapping_sheet_id}"
    <br>Note that no data will be uploaded to Gateway until this issue is fixed. Details below:<br><ul>"""

    failure_map = ti.xcom_pull(**email_metadata_xcom_args)

    for field_name, failures in failure_map.items():
        message += f"<li>{field_name}</li>"
        message += format_validation_failures(failures)
    message += "</ul>"

    email_content = HEADER + message
    log_email(contact_email, email_content)

    if contact_email:
        send_email(
            contact_email,
            subject_header,
            email_content,
            mime_subtype="mixed",
            mime_charset="utf8",
        )
Ejemplo n.º 11
0
def _send_email(**context):
    ti = context['ti']
    msg = ti.xcom_pull(task_ids='rclone_copy', key='number_of_files')
    new_folders = ti.xcom_pull(task_ids='new_folders_check', key='new_folders')

    num_folders = len(new_folders) if new_folders else 0
    status = 'Backup Succeeded' if num_folders else 'Nothing New'

    html_content = """
        <h2>SickKids Dropbox Backup Notfication</h2>
        <p>Status: {status}</p>
        <p>Date: {date}</p>
        <p>Number of folders backed up: {num_folders}</p>
        <p>Folders: {folders}</p>
    """.format(status=status,
               date=context['ds'],
               num_folders=num_folders,
               folders=new_folders)

    subject = 'SickKids Airflow: %s (%s)' % (status, context['ds'])

    print "Sending email: \n\n\tSubject: %s\n%s" % (subject, html_content)

    send_email(to=['*****@*****.**'],
               subject=subject,
               html_content=html_content)
Ejemplo n.º 12
0
def notify_email():
    barcodes = []

    if not os.path.exists(VIDEO_LIST):
        log.error("Video list file '%s' doesn't exists" % VIDEO_LIST)
        raise Exception

    with open(VIDEO_LIST, 'r') as video_list_file:
        video_list = json.load(video_list_file)

    for barcode, path in video_list.items():
        barcodes.append(barcode)

    if len(barcodes) > 1:
        email_title = "Task with videos %s has been finished!" % ", ".join(
            barcodes)
    else:
        email_title = "Task with video %s has been finished!" % barcodes[0]

    email_body = """
    Dear AV team, <br>
    <br>
    Archival Information Package for the following videos are ready:<br/><br/>
    <i>%s</i><br/><br/>
    Your sincerely,<br>
    AV workflow<br>
    """ % "<br/>".join(barcodes)

    emails = AV_STAFF_EMAIL_LIST.split(',')
    send_email(emails, email_title, email_body)
Ejemplo n.º 13
0
 def _send_email_password_updated(self, new_pass, email_to_list):
     """Envia email para admins informando a nova senha após atualização
     """
     subject = "Atualização da senha da WS do BACEN (STA)"
     dag_id = 'update_password_sta_bacen'
     dag_url = f'http://airflow.seges.mp.intra/tree?dag_id={dag_id}'
     content = f"""
         Olá!
         <br>
         <br>
         A senha utilizada pelas dags que acessam arquivos no BACEN
         via o STA foi atualizada.
         <br>
         <br>
         A nova senha é: <b>{new_pass}</b>
         <br>
         O login é: <b>841260010.NITAI</b>
         <br>
         Caso queira testar acesse:
         <a href="https://sta.bcb.gov.br/"
            target="_blank">https://sta.bcb.gov.br/</a>
         <br>
         <br>
         Esta mensagem foi enviada pela dag <b>{dag_id}</b>.
         <br>
         Para acessar: <a href="{dag_url}" target="_blank">{dag_url}</a>
         <br>
         <br>
         Airflow-bot.
         <br>
         <br>
     """
     send_email(to=email_to_list,
                subject=subject,
                html_content=replace_to_html_encode(content))
Ejemplo n.º 14
0
def email_failures(task_instance, ds, **kwargs):
    if is_development():
        print("Skipping since in development mode!")
        return

    status = task_instance.xcom_pull(task_ids="download_data")
    error_agencies = status["errors"]

    if len(error_agencies) > 0:
        html_report = pd.DataFrame(error_agencies).to_html(border=False)

        html_content = f"""\
The following agency GTFS feeds could not be extracted on {ds}:

{html_report}
"""
    else:
        html_content = "All feeds were downloaded successfully!"

    send_email(
        to=[
            "*****@*****.**",
            "*****@*****.**",
            "*****@*****.**",
            "*****@*****.**",
            "*****@*****.**",
            "*****@*****.**",
            "*****@*****.**",
        ],
        html_content=html_content,
        subject=
        (f"Operator GTFS Errors for {datetime.datetime.now().strftime('%Y-%m-%d')}"
         ),
    )
Ejemplo n.º 15
0
    def execute(self, context):

        (
            fetch_record_count,
            send_data_to_submission,
        ) = context['ti'].xcom_pull(key='exception',
                                    task_ids=('fetch_record_count',
                                              'send_data_to_submission'))

        if fetch_record_count is None:
            message = '<img src="https://airflow.apache.org/images/feature-image.png" width="400" height="100"/>' \
                      '<h2>AIRFLOW TASK FAILURE:</h2><hr/>' \
                      '<strong>DAG : </strong>    {} <br/><hr/>' \
                      '<strong>TASKS:</strong>  {}<br/><hr/>' \
                      '<strong>Reason:</strong> {}<br/><hr/>' \
                .format(self.dag_id, 'send_data_to_submission', send_data_to_submission)
        elif send_data_to_submission is None:
            message = '<img src="https://airflow.apache.org/images/feature-image.png" width="400" height="100"/>' \
                      '<h2>AIRFLOW TASK FAILURE:</h2><hr/>' \
                      '<strong>DAG : </strong>    {} <br/><hr/>' \
                      '<strong>TASKS:</strong>  {}<br/><hr/>' \
                      '<strong>Reason:</strong> {}<br/><hr/>' \
                .format(self.dag_id, 'fetch_record_count', fetch_record_count)

        try:
            config = json.loads(Variable.get("config"))
            email = config['email']
        except NameError as e:
            raise ConfigVariableNotFoundException()

        send_email(to=email,
                   subject='Airflow Notification',
                   html_content=message)
Ejemplo n.º 16
0
def mail_files(to, subject, debug_to=None, content='', cc=None, file_task='gen_excel', **kwargs):
    if not ENABLE_EMAIL and not debug_to:
        return

    result_txt = kwargs['ti'].xcom_pull(task_ids=file_task)
    logging.info(result_txt)
    result = json.loads(result_txt)

    if result['status'] != 'success' or \
        len(result['data']['files']) == 0:
        return

    files = result['data']['files']
    subject = subject.format(ds=ds(kwargs['ti']))
    cc = cc + EMAIL_DEFAULT_CC if cc else EMAIL_DEFAULT_CC
    html_content = EMAIL_TMPL.format(content)

    if debug_to and not IS_PRD:
        to = debug_to
        cc = None

    send_email(to=to
        , subject=subject
        , html_content=html_content
        , files=files
        , cc=cc
        , mime_charset='utf-8'
    )
Ejemplo n.º 17
0
 def email_callback(df):
     df = pd.read_csv(io.StringIO(df))
     files = glob.glob("figures/*.png")
     content = build_table(df, 'blue_light')
     send_email(to=["*****@*****.**"],
                subject='Report',
                html_content=content,
                files=files)
Ejemplo n.º 18
0
        def email_alert(task_instance, error_info):
            try:
                subject, html_content, _ = task_instance.get_email_subject_content(error_info)
                email = sensor_work.execution_context.get('email')

                send_email(email, subject, html_content)
            except Exception:  # pylint: disable=broad-except
                sensor_work.log.warning("Exception alerting email.", exc_info=True)
Ejemplo n.º 19
0
 def sendEmail():
     files = glob.glob("test/*.pdf")
     print(files)
     content = '<h1>Radar</h1><br>' + str(kw) + '<br>' + str(files)
     send_email(to=receiversList[0],
                bcc=receiversList[1:],
                subject='Radar Test ' + str(kw),
                html_content=content,
                files=files)
Ejemplo n.º 20
0
 def execute(self, context):
     send_email(self.to,
                self.subject,
                self.html_content,
                files=self.files,
                cc=self.cc,
                bcc=self.bcc,
                mime_subtype=self.mime_subtype,
                mime_charset=self.mime_charset)
def callable_func(context):
    print(context)
    dag_id = context.get('task_instance').dag_id
    task_id = context.get('task_instance').task_id
    log_url = context.get('task_instance').log_url
    log_filepath = context.get('task_instance').log_filepath
    exec_date = context.get('execution_date')

    email_title = """
    Airflow Alert-- Airflow Task {task_id} is Success
    """.format(task_id=task_id)

    email_body = """
    <table class="reportWrapperTable" cellspacing="4" cellpadding="2" width="100%" rules="rows" style="border-collapse:collapse;color:#1f2240;background-color:#ffffff">
    <caption style="background-color:#ffffff;color:#1f2240;margin-bottom:.5em;font-size:18pt;width:100%;border:0">Airflow Alert</caption>
    <thead style="100%;color:#ffffff;background-color:#1f2240;font-weight:bold">
    <tr>
    <th scope="col" style="background-color:#1f2240">Name</th>
    <th scope="col" style="background-color:#1f2240">Status</th>
    </tr>
    </thead>
    <tbody>

    <tr>
    <td>The Task: </td>
    <td>{task_id}</td>
    </tr>
    
    <tr>
    <td>The Dag: </td>
    <td>{dag_id}</td>
    </tr>

    <tr>
    <td>Execution Time: </td>
    <td>{exec_date}</td>
    </tr>

    <tr>
    <td>Status: </td>
    <td> <span style="font-size: 20px; color: #008000;">
    Success.
    </span>
    </td>
    </tr>

    <tr>
    <td>Log Url: </td>
    <td><a href="{log_url}">Link</a></td>
    </tr>
    </tbody></table>
    """.format(task_id=task_id,
               dag_id=dag_id,
               log_url=log_url,
               exec_date=exec_date)
    to = TO_MAIL
    send_email(to, email_title, email_body)
def notify_email(contextDict, **kwargs):
    title = "Airflow alert: file does not exist.".format(**contextDict)
    body = """
    Hi Everyone, <br>
    <br>
    There's been an error in the data_exist job. No data available. <br>
    <br>Please, fix it.    
    """.format(**contextDict)
    send_email('*****@*****.**', title, body)
Ejemplo n.º 23
0
def send_bdm_dim_file_email(ds, ds_nodash, **kwargs):
    cursor = get_hive_cursor()
    sql = """
        select  
        dt,
        area_name,
        --points,
        bdm_name,
        hbdm_name,
        take_time_avg,
        delivery_time_avg,
        score_peisong_avg,
        cancel_order_cnt,
        concat(cast(nvl(round(sys_cancel_order_cnt * 100 / cancel_order_cnt,1),0) as string),'%'),
        concat(cast(nvl(round(user_cancel_order_cnt * 100/cancel_order_cnt,1),0) as string),'%'),
        concat(cast(nvl(round(merchant_cancel_order_cnt * 100/cancel_order_cnt,1),0) as string),'%')
        
        from ofood_bi.ofood_bdm_area_metrics_report 
        where dt = '{dt}' 

    """.format(dt=ds, ds=ds_nodash)

    headers = [
        'day',
        'area_name',
        #'points',
        'bdm_name',
        'hbdm_name',
        'time_pick',
        'time_peisong',
        'score_peisong',
        'total_cancle',
        'total_auto_cancle',
        'total_merchant_cancle',
        'total_user_cancle'
    ]

    logging.info('Executing: %s', sql)
    cursor.execute(sql)
    rows = cursor.fetchall()

    file_name = '/tmp/ofood_bdm_dim_metrics_{dt}.csv'.format(dt=ds)
    with codecs.open(file_name, 'w', 'utf_8_sig') as f:
        f_csv = csv.writer(f)
        f_csv.writerow(headers)
        f_csv.writerows(rows)

    # send mail
    email_to = Variable.get("ofood_honour_metrics_receivers").split()
    # email_to = ['*****@*****.**']
    email_subject = 'ofood-BDM履约每日数据_{dt}'.format(dt=ds)
    email_body = 'ofood-BDM履约每日数据'
    send_email(email_to,
               email_subject,
               email_body, [file_name],
               mime_charset='utf-8')
Ejemplo n.º 24
0
 def send_email_notification(self, email_content):
     send_email(self.email_to,
                'expectations in suite ' + self.expectation_suite_name +
                ' not met',
                email_content,
                files=None,
                cc=None,
                bcc=None,
                mime_subtype='mixed',
                mime_charset='us_ascii')
Ejemplo n.º 25
0
def alert_deaths(**context):

    # Fetch the cleaned DataFrame from the above XCOM
    df = context["ti"].xcom_pull(key="df")
    email = context["ti"].xcom_pull(key="email")

    if df.head(n=1).loc[df['positive'] > 200000,
                        'More than 7 million cases'] == True:
        send_email(email, "U.S. Cases Exceed 7 million", cases_body)
    else:
        pass
Ejemplo n.º 26
0
def alert_cases(**context):

    # Fetch the cleaned DataFrame from the above XCOM
    df = context["ti"].xcom_pull(key="df")
    # Send email if cases exceed 7 million
    cases = df['positive'] > 7000000

    if cases.bool():
        send_email(email, "U.S. Cases Exceed 7 million", cases_body)
    else:
        pass
Ejemplo n.º 27
0
    def execute(self, context):

        message = "<h3> Dag Successfull </h3>"
        try:
            config = json.loads(Variable.get("config"))
            email = config['email']
        except NameError as e:
            raise ConfigVariableNotFoundException()

        send_email(to=email,
                   subject='Airflow Notification',
                   html_content=message)
Ejemplo n.º 28
0
def send_alert_email(mark, context, raise_exception=False):
    title = "[%s] %s@%s: Airflow alert" % (mark, context["dag"].dag_id,
                                           context["ti"].hostname)
    body = ("Log: <a href='{ti.log_url}'>Link</a><br>"
            "Host: {ti.hostname}<br>"
            "Log file: {ti.log_filepath}<br>").format(**{"ti": context["ti"]})
    try:
        send_email(context["task"].email, title, body)
    except Exception as e:
        logging.exception("send email failed")
        if raise_exception:
            raise e
Ejemplo n.º 29
0
 def execute(self, context: Context):
     send_email(
         self.to,
         self.subject,
         self.html_content,
         files=self.files,
         cc=self.cc,
         bcc=self.bcc,
         mime_subtype=self.mime_subtype,
         mime_charset=self.mime_charset,
         conn_id=self.conn_id,
         custom_headers=self.custom_headers,
     )
Ejemplo n.º 30
0
def send_shop_list_file_email(ds, ds_nodash, **kwargs):
    cursor = get_hive_cursor()
    sql = """
        select  
        dt,
        shop_id,
        title,
        bd_name,
        bdm_name,
        hbdm_name,
        his_order_cnt,
        if(closed = 0,'Y','N'),
        if(is_new_user_act = 1,'Y','N'),
        if(is_promotion_act = 1,'Y','N'),
        yy_peitime,
        product_cnt,
        addr,
        account_number
        
        from ofood_bi.ofood_shop_list_metrics_report 
        where dt = '{dt}' 

    """.format(dt=ds, ds=ds_nodash)

    headers = [
        'day', 'shop_id', 'title', 'bd_name', 'bdm_name', 'hbdm_name',
        'his_order_cnt', 'is_open(Y or N)', 'activity_of_new_user(Y or N)',
        'activity_of_promotion(Y or N)', 'business_time', 'menu_item',
        'location', 'opay_account'
    ]

    logging.info('Executing: %s', sql)
    cursor.execute(sql)
    rows = cursor.fetchall()

    file_name = '/tmp/ofood_shop_list_metrics_{dt}.csv'.format(dt=ds)
    with codecs.open(file_name, 'w', 'utf_8_sig') as f:
        f_csv = csv.writer(f)
        f_csv.writerow(headers)
        f_csv.writerows(rows)

    # send mail
    email_to = Variable.get("ofood_honour_metrics_receivers").split()
    # email_to = ['*****@*****.**']
    email_subject = 'ofood-商家明细List每日数据_{dt}'.format(dt=ds)
    email_body = 'ofood-商家明细List每日数据'
    send_email(email_to,
               email_subject,
               email_body, [file_name],
               mime_charset='utf-8')
 def execute(self, context):
     send_email(self.to, self.subject, self.html_content,
                files=self.files, cc=self.cc, bcc=self.bcc,
                mime_subtype=self.mime_subtype, mime_charset=self.mime_charset)
Ejemplo n.º 32
0
    def manage_slas(self, dag, session=None):
        """
        Finding all tasks that have SLAs defined, and sending alert emails
        where needed. New SLA misses are also recorded in the database.

        Where assuming that the scheduler runs often, so we only check for
        tasks that should have succeeded in the past hour.
        """
        TI = models.TaskInstance
        sq = (
            session
            .query(
                TI.task_id,
                func.max(TI.execution_date).label('max_ti'))
            .filter(TI.dag_id == dag.dag_id)
            .filter(TI.state == State.SUCCESS)
            .filter(TI.task_id.in_(dag.task_ids))
            .group_by(TI.task_id).subquery('sq')
        )

        max_tis = session.query(TI).filter(
            TI.dag_id == dag.dag_id,
            TI.task_id == sq.c.task_id,
            TI.execution_date == sq.c.max_ti,
        ).all()

        ts = datetime.now()
        SlaMiss = models.SlaMiss
        for ti in max_tis:
            task = dag.get_task(ti.task_id)
            dttm = ti.execution_date
            if task.sla:
                dttm = dag.following_schedule(dttm)
                while dttm < datetime.now():
                    following_schedule = dag.following_schedule(dttm)
                    if following_schedule + task.sla < datetime.now():
                        session.merge(models.SlaMiss(
                            task_id=ti.task_id,
                            dag_id=ti.dag_id,
                            execution_date=dttm,
                            timestamp=ts))
                    dttm = dag.following_schedule(dttm)
        session.commit()

        slas = (
            session
            .query(SlaMiss)
            .filter(SlaMiss.email_sent == False or SlaMiss.notification_sent == False)
            .filter(SlaMiss.dag_id == dag.dag_id)
            .all()
        )

        if slas:
            sla_dates = [sla.execution_date for sla in slas]
            qry = (
                session
                .query(TI)
                .filter(TI.state != State.SUCCESS)
                .filter(TI.execution_date.in_(sla_dates))
                .filter(TI.dag_id == dag.dag_id)
                .all()
            )
            blocking_tis = []
            for ti in qry:
                if ti.task_id in dag.task_ids:
                    ti.task = dag.get_task(ti.task_id)
                    blocking_tis.append(ti)
                else:
                    session.delete(ti)
                    session.commit()

            blocking_tis = ([ti for ti in blocking_tis
                            if ti.are_dependencies_met(session=session)])
            task_list = "\n".join([
                sla.task_id + ' on ' + sla.execution_date.isoformat()
                for sla in slas])
            blocking_task_list = "\n".join([
                ti.task_id + ' on ' + ti.execution_date.isoformat()
                for ti in blocking_tis])
            # Track whether email or any alert notification sent
            # We consider email or the alert callback as notifications
            email_sent = False
            notification_sent = False
            if dag.sla_miss_callback:
                # Execute the alert callback
                self.logger.info(' --------------> ABOUT TO CALL SLA MISS CALL BACK ')
                dag.sla_miss_callback(dag, task_list, blocking_task_list, slas, blocking_tis)
                notification_sent = True
            email_content = """\
            Here's a list of tasks thas missed their SLAs:
            <pre><code>{task_list}\n<code></pre>
            Blocking tasks:
            <pre><code>{blocking_task_list}\n{bug}<code></pre>
            """.format(bug=asciiart.bug, **locals())
            emails = []
            for t in dag.tasks:
                if t.email:
                    if isinstance(t.email, basestring):
                        l = [t.email]
                    elif isinstance(t.email, (list, tuple)):
                        l = t.email
                    for email in l:
                        if email not in emails:
                            emails.append(email)
            if emails and len(slas):
                send_email(
                    emails,
                    "[airflow] SLA miss on DAG=" + dag.dag_id,
                    email_content)
                email_sent = True
                notification_sent = True
            # If we sent any notification, update the sla_miss table
            if notification_sent:
                for sla in slas:
                    if email_sent:
                        sla.email_sent = True
                    sla.notification_sent = True
                    session.merge(sla)
            session.commit()
            session.close()
Ejemplo n.º 33
0
 def execute(self, context):
     send_email(self.to, self.subject, self.html_content, files=self.files)