0
0

【crontab】EC2のcrontab -> Pythonスクリプト実行 -> RDSのストプロ -> Slackへ通知、という流れを構築する

Posted at

概要

EC2のcrontab -> Pythonスクリプト実行 -> RDSのストプロ -> Slackへ通知、という流れを構築しました。

具体的には、
「毎日9時に、プロシージャで実施した結果を、指定のSlackチャンネルに通知する」
という流れがゴールです。

今回は、AWSのEC2サーバでクーロンを利用してPythonスクリプトを定期的に実行させる方法になります。Pythonスクリプトの実行はRDSのストプロを呼び出し、SQL結果を特定のSlackチャンネルに通知します。

構築手順と注意点を解説します。

手順

まず、EC2サーバに今回のツール用のディレクトリを作成します。
ここでは、とあるDBテーブルからレコード数をカウントするツールを例にしますので、ディレクトリ名はcount-number-toolとします。

その下に、以下の3つを作成していきます。

count-number-tool
├── venv
├── number-counter.py
└── run_script.sh

venvの作成

まずは仮想環境を作成します。
サーバ全体に影響を与えずにパッケージをインストールしたいためです。
(個別にインストールするライブラリがない場合は不要です)

以下のコマンドで仮想環境を作成しましょう。

python3 -m venv venv

※もし、まだpythonがインストールされていない場合は以下のコマンドでインストールしましょう

sudo yum install -y python3

仮想環境を作成したらアクティベートします。

source venv/bin/activate

利用したいライブラリをインストールしましょう。
例えば、以下のような感じです。

pip install pymysql
pip install requests

run_script.shの作成

run_script.shは、クーロンで呼び出すスクリプトです。
以下のように、仮想環境の起動&Pythonスクリプトの実行、を記載します。

run_script.sh
#!/bin/bash
source /home/ec2-user/count-number-tool/venv/bin/activate
python /home/ec2-user/count-number-tool/number-counter.py
deactivate

シェルスクリプトには実行権限を与えておきます。

chmod +x /home/ec2-user/count-number-tool/run_script.sh

number-counter.pyの作成

実行したいPythonスクリプトを書きます。
今回は、count_numberというプロシージャを実行して、その結果をSlackに通知するコードにしています。

import json
import os
from datetime import datetime, timedelta
import pymysql
import requests
import logging
from decimal import Decimal

logger = logging.getLogger()
logger.setLevel(logging.INFO)

rds_host = 'xxx'
rds_user = 'xxx'
rds_password = 'xxx'
rds_db = 'xxx'
slack_webhook_url = 'https://hooks.slack.com/services/xxx'

def send_slack_notification(webhook_url, message):
    payload = {
        "text": message
    }
    response = requests.post(webhook_url, data=json.dumps(payload), headers={'Content-Type': 'application/json'})
    if response.status_code != 200:
        raise ValueError('Request to Slack returned an error {}, the response is:\n{}'.format(response.status_code, response.text))

def decimal_default(obj):
    if isinstance(obj, Decimal):
        return float(obj)
    raise TypeError

def main():
    logger.info("Script started")
    
    today = datetime.now()
    yesterday = today - timedelta(1)
    report_date = yesterday.strftime('%Y-%m-%d')
    logger.info("Report date: {}".format(report_date))
    
    try:
        connection = pymysql.connect(host=rds_host, user=rds_user, password=rds_password, db=rds_db)
        logger.info("Connected to RDS")
    except Exception as e:
        logger.error("Error connecting to RDS: {}".format(e))
        raise
    
    try:
        with connection.cursor() as cursor:
            cursor.callproc('count_number', [report_date])
            result = cursor.fetchall()
            logger.info("Stored procedure result: {}".format(result))
            
            if result:
                row = result[0]
                message = "Report for {}:\n".format(report_date)
                message += "hoge, foo, example, sample, test\n"
                message += "{},{},{},{},{},{}\n".format(row[0], row[1], row[2], row[3], row[4])
                send_slack_notification(slack_webhook_url, message)
                logger.info("Slack notification sent"
            
    finally:
        connection.close()
        logger.info("RDS connection closed")
    
    return {
        'statusCode': 200,
        'body': json.dumps(result, default=decimal_default)
    }

if __name__ == "__main__":
    main()

※EC2サーバはRDSへアクセスできる状態である必要があります。セキュリティグループで許容していることを確認してください

RDSのストプロ例

以下は、sample_tableのcreate_dateカラムが前日のもので、かつ、sample_noカラムに指定の文字列から始まるレコードが何件あるか、というSQLになります。上述のPythonスクリプトで以下のプロシージャを実行します。

count_number.sql
CREATE DEFINER=`root`@`%` PROCEDURE `sample`.`count_number`(IN report_date DATE)
BEGIN
    SELECT 
        SUM(CASE WHEN sample_no LIKE 'hoge%' THEN 1 ELSE 0 END) AS count_hoge,
        SUM(CASE WHEN sample_no LIKE 'foo%' THEN 1 ELSE 0 END) AS count_foo,
        SUM(CASE WHEN sample_no LIKE 'example%' THEN 1 ELSE 0 END) AS count_example,
        SUM(CASE WHEN sample_no LIKE 'sample%' THEN 1 ELSE 0 END) AS count_sample,
        SUM(CASE WHEN sample_no LIKE 'test%' THEN 1 ELSE 0 END) AS count_test
    FROM mysql57.sample_table  
    WHERE create_date BETWEEN CONCAT(report_date, ' 00:00:00') AND CONCAT(report_date, ' 23:59:59');
END

crontabの設定

EC2サーバで以下を実行し、Cronジョブを設定します。

crontab -e

crontab コマンドは、cron ジョブの実行のほか、編集、リスト、除去を行います。 cron ジョブとは、cron デーモンによりスケジュールされ、一定の周期で実行されるジョブです。 cron ジョブの実行を要求するには、crontab コマンドに -e フラグを指定します。 crontab コマンドは、編集セッションを起動します。この編集セッションで、crontab ファイルを作成できます。
https://www.ibm.com/docs/ja/aix/7.2?topic=c-crontab-command

ジョブは以下のように追加します。

00 9 * * * /home/ec2-user/count-number-tool/run_script.sh

上記は、毎朝9時に、run_script.shを実行する、というもの。
これにより、Pythonスクリプトが定期的に実行され、Slackへ毎朝結果が届くようになりました。

参考

AWS Lambdaを利用して構築する手順も以前に記事にしました。ご参考までに。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0