从Snowflake发送电子邮件警报

时间:2020-07-20 06:33:43

标签: snowflake-cloud-data-platform

如果Snowflake中的存储过程失败,有什么方法可以发送电子邮件警报? 当我查看雪花文档时,在雪花中没有提及电子邮件实用程序

3 个答案:

答案 0 :(得分:4)

您可以直接从 Snowflake 发送电子邮件,也可以选择将表/视图中的数据作为附件发送。这是使用 Snowflake External 函数完成的,该函数又通过 AWS Gateway 调用 AWS Lambda 函数。 第一步是设置 AWS 网关。您可以按照以下说明进行操作: Creating a Customizable External Function on AWS

如果您在 Snowflake 中使用了示例函数,则您已经成功地为添加电子邮件功能奠定了基础。接下来是设置一个 S3 存储桶来创建需要作为电子邮件附件发送的数据文件。

  1. 创建一个名为“snowapi”的 AWS S3 存储桶。我们不需要将此存储桶公开给互联网,因此将“阻止所有公共访问”设置为开启。

  2. 现在您需要提供对该存储桶的 Snowflake 访问权限。创建 IAM 用户“雪花”。添加权限 -> 附加退出策略:AmazonS3FullAccess。转到“安全凭据”选项卡和“创建访问密钥”。使用以下命令中的访问密钥 ID 和秘密访问密钥将数据卸载到 S3 存储桶中。

    创建或替换 UTIL.AWS_S3_STAGE URL='s3://snowapi/' 凭据=(AWS_KEY_ID='ABCD123456789123456789' AWS_SECRET_KEY='ABCD12345678901234567890123456789');

    复制到@UTIL.AWS_S3_STAGE/outbound/SampleData.csv 从 文件格式 = 覆盖 = 真 单 = 真;

  3. 下一步是使用下面的 Nodejs 代码创建一个新的 Lambda 函数。请注意,这使用了 SENDGRID API。 Sendgrid 有一个永久免费层,每天 100 封电子邮件。我在本地安装了这个库并将 uploaded the zip 文件安装到 AWS 以创建 Lambda 函数。

//Lambda Function name: email
const sgMail = require('@sendgrid/mail');
var AWS = require('aws-sdk');
var s3 = new AWS.S3();
 
exports.handler =  async (event, context, callback) => {
  sgMail.setApiKey(process.env.SENDGRID_KEY);
 
  const paramArray = JSON.parse(event.body).data[0];
  //paramArray[0] has the row number from Snowflake
  var message = {
        to: paramArray[1].replace(/\s/g, '').split(','),
        from: paramArray[2].replace(/\s/g, ''),
        subject: paramArray[3],
        html: paramArray[4]
      };
  
  // Attach file
  if (paramArray.length > 5) {
    var fileName = paramArray[5].substring(paramArray[5].lastIndexOf("/")+1);
    var filePath = paramArray[5].substring(0, paramArray[5].lastIndexOf("/"));
    try {
      const params = {Bucket: process.env.BUCKET_NAME + filePath, Key: fileName};
      const data = await s3.getObject(params).promise();
      var fileContent = data.Body.toString('base64');
    } catch (e) {
      throw new Error(`Could not retrieve file from S3: ${e.message}`);
    }
    message.attachments = [{content: fileContent,
                            filename: fileName,
                            type: "application/text",
                            disposition: "attachment"
                          }];
  }
    
  try{
      await sgMail.send(message);
      return {
          'statusCode': 200,
          'headers': { 'Content-Type': 'application/json' },
          'body' : "{'data': [[0, 'Email Sent to "+ paramArray[1] + "']]}" 
      };
    } catch(e){
      return {
          'statusCode': 202,
          'headers': { 'Content-Type': 'application/json' },
          'body' : "{'data': [[0, 'Error - " + e.message + "']]}" 
      };
    } 
 
};

  1. 为 Lambda 函数设置以下两个环境变量:

     SENDGRID_KEY: <sendgrid_api_key>
     BUCKET_NAME: snowapi
    
  2. 创建雪花外部函数:

     create or replace external function util.aws_email
     (mailTo varchar,mailFrom varchar,subject varchar,htmlBody varchar,fileName varchar)
     returns variant
     api_integration = aws_api_integration
     as 'https://xxxxxxxxxx.execute-api.us-east-1.amazonaws.com/PROD/email';
    
  3. 为上述外部函数创建一个包装程序:

     create or replace procedure util.sendemail
     (MAILTO varchar,MAILFROM varchar,SUBJECT  varchar,HTMLBODY varchar,FILENAME varchar)
     returns string
     language javascript
     EXECUTE AS OWNER
     as
     $$
       // Call the AWSLambda function.
       var qry = "select util.aws_email(:1,:2,:3,:4,:5)"; 
    
       // null should be in lowercase. 
       var stmt = snowflake.createStatement({sqlText: qry, 
                                             binds: [MAILTO,
                                                     MAILFROM||'no-reply@yourdomain.com',
                                                     SUBJECT ||'Email sent from Snowflake',
                                                     HTMLBODY||'<p>Hi there,</p> <p>Good luck!</p>',
                                                     FILENAME||null]
                                           });
       var rs;
       try{
           rs = stmt.execute();
           rs.next();
           return rs.getColumnValue(1);
       }
       catch(err) {
         throw "ERROR: " + err.message.replace(/\n/g, " ");
       }
     $$;
    
  4. 一切就绪!最终结果是一个干净的电话,发送电子邮件如下。

     Call SENDEMAIL('to_email@dummy.com, to_another_email@dummy.com',
                     'from@yourdomain.com', 
                     'Test Subject',
                     'Sample Body');
    

祝你好运!!

答案 1 :(得分:2)

我相信Snowflake中没有电子邮件实用程序,但是您可以使用python运行雪花存储过程,并根据可以触发来自python的邮件的状态检查存储过程状态。

答案 2 :(得分:0)

我们使用bash脚本中的snowsql命令,并在命令行上使用“ -o exit_on_error = true”选项,并在步骤结束时检查返回代码。如果Snowflake命令失败,则错误退出设置将意味着Snowflake将在错误发生时停止并将控制权返回给调用程序。

如果返回码为零,那么我们进入下一步。

如果它不是零,那么我们将调用一个错误处理程序,该处理程序发送电子邮件,然后退出作业。

我们正在使用Amazon Linux进行编排,并且我们将mutt用作电子邮件应用程序。