🤖

Node.js・AWS Lambda・Amazon EventBridgeで定期的に特定の言葉をツイートさせる!

2022/05/04に公開

AWSについて少し勉強していたら、AWS Lambdaを知りました。
面白そうだったので、ちょっと勉強から脱線して...
Node.js・AWS Lambda・Amazon EventBridgeを使って、定期的にツイートが実行される、いわゆるBotの開発に挑戦してみました!!
折角なので、記事にして記録しておこうと思います!

※新たにアカウントを作成せずに、現在利用しているアカウントに組み込んだので、「Bot風」という表現の方が正しいかもしれないです。

作ったもの

毎日、日本時間の19時になったら「今日もお疲れ様でした〜😆」とツイートするBotを開発しました。
前述のように、今回のBot用のアカウントは作っていないので、私のアカウントはBotで自動的にツイートしているものと手動でツイートしているものが混ざった状態になってます笑

https://twitter.com/azunyan_eng/status/1521791810540302336?s=21&t=aULQThiid9qPha57EW9qfw

AWS Lambda

早速、AWS Lambdaを使ってみたいと思います!

AWS Lambdaとは?

サーバの構築や管理が不要で、ソースコードを作成してアップロードするだけで、プログラムを実行できるサービスです。
C#や、Java、Node.js、Pythonなどの言語・実行環境が利用できます。

AWS Lambdaで関数を作る

AWS Lambdaの関数ページで関数の作成ボタンをクリックすると以下の画像のようなページに遷移します。
任意の関数名を入力し、ランタイムでNode.jsを選択します。
その他の部分は、デフォルトのままで特に問題はないかなと思うので、右下の「関数の作成」をクリックしてしまいます。

これで、AWS Lambda上で関数を作成することができました!

Twitter APIを利用してツイートできるようにする

それでは、肝心のツイートを実行するためのコードを書いていきます。
まず、Node.jsでTwitter APIを利用するためのnpmパッケージを導入します。

npm install --save twitter

あとでAWS Lambda上で設定する環境変数を用いて、認証を行います。

const Twitter = require('twitter');

const client = new Twitter({
    consumer_key: process.env.CONSUMER_KEY,
    consumer_secret: process.env.CONSUMER_SECRET,
    access_token_key: process.env.ACCESS_TOKEN_KEY,
    access_token_secret: process.env.ACCESS_TOKEN_SECRET,
});

引数として渡しているオブジェクトのプロパティは以下の4つです。

キー名
consumer_key API Key
consumer_secret API Secret
access_token_key Access Token
access_token_secret Access Token Secret

ツイートを実行する関数を作成していきます。postメソッドを使い、第1引数にendpointを指定し、第2引数にツイートする内容をオブジェクト形式で渡しています。
同じ内容のツイートは複数回できないようになっているので、new Date()を使って生成した日付も一緒にツイートするようにしています。

exports.handler = () => {
    const date = new Date().toLocaleString('ja-JP');
    const text = '今日もお疲れ様でした〜😆'
    const tweetText = { status: `${text}\r\n${date}` }

    client.post('statuses/update', tweetText, (error, tweet, response) => {
        if (error) throw error;
    });
}

処理を記述したjsファイルとnode_modulesをまとめて.zipファイル化します。

zip -r 任意の.zipファイル名.zip ./初期を記述したファイル名.js ./node_modules/

AWS Lambdaにデプロイする

それでは、AWS Lambdaに作成したコードをデプロイしていきます!
.zipファイルを直接AWS Lambdaにアップロードするか、S3に配置するかのどちらかで、ローカルで作成したソースコードをデプロイすることができます。
コンテナイメージも利用できるようですが、割愛します。

.zipファイルのアップロード

.zipファイルをアップロードします。
AWS Lambdaの関数で、コードソースという部分があります。
その部分の右上に「アップロード元」というボタンを探して、クリックすると、「.zipファイル」と「Amazon S3の場所」の2つの選択が出てくると思います。その2つのうち、「.zipファイル」を選択してください。

すると、.zipファイルをアップロードするためのモーダルが出てくるので、アップロードボタンを押して.zipファイルを選択し、保存してください。

これで、AWS Lambdaに.zipファイルをアップロードすることができました!

AWS Lambdaで環境変数を設定する

設定ページに遷移し、環境変数を設定できるので、こちらで、先にメモしておいた、API Key/API Secret、Access Token/Access Token Secretを環境変数として登録します。

また、ツイート内に表示する時刻を合わせるために、タイムゾーンを環境変数で指定する必要がありました!
キーをTZに、値をAsia/Tokyoにして環境変数を追加してください。

Amazon EventBridge

定期的にツイートするようにしたいので、EventBridgeを使って定期的に関数が動くように設定していきます。

Amazon EventBridgeとは?

作成したルールと一致するイベントを受信したら、指定されたターゲットが呼び出されて処理が実行されるサービスです。
Amazon CloudWatchで提供されているAmazon CloudWatch Eventsという機能を拡張したサービスが、今回使用するAmazon EventBridgeです。

定期実行できるようにAmazon Event Bridgeを設定する

AWS Lambdaの関数の概要部分に、「トリガーを追加」というボタンがあると思うので、クリックしてください。

トリガーとして、EventBridgeを選択してください。

ルールは、新規ルールの作成を選択します。任意のルール名を入力してください。
今回は、特定の時間になるとツイートするようにしたいので、ルールタイプでは「スケジュール式」を選択します。

スケジュール式の書き方は、cron式を利用します。

cronとは?

cronとは、cron式で指定した時間になると、プログラムを実行してくれるツールです。
バッチ処理のような、定期的にプログラムを実行する時などに使われたりします。

cron式では、分や時間、日付など6つの要素を空白区切りで指定していきます。

cron(分 時間 日付 月 曜日 年)

今回の場合は、以下のようなcron式になりました。
日付と曜日の両方にアスタリスク(✳︎)を指定することはできないことになっているので、日付には疑問符(?)を入れています。
また、時間は、GMT(グリニッジ標準時)が採用されているので、日本時間 - 9時間をした値を入れます。
日本時間で19時にツイートさせたいので、19 - 910を時間のフィールドに入れています。

cron(0 10 ? * * *)

何種類かワイルドカードがあるので、それらと値を組み合わせて指定していきます。
以下が、ワイルドカードの例です。

ワイルドカード 説明
,(カンマ) 値を追加する。
-(ダッシュ) 範囲を指定する。
*(アスタリスク) 全ての値。
/(スラッシュ) 間隔を指定する。「10分経過ごと」など。
?(疑問符) 任意の値。特定の日付や曜日がない場合など。

cron式について、AWSの公式ドキュメントでも詳しく説明されているので、参照してみてください。

おまけ〜ローカルでテストしたい!〜

AWS Lambdaでもテストはできるのですが、何度もアップロードしたくないですし、できればローカルでテストしたいと思いますよね。
その場合、API Key/API Secret、Access Token/Access Token Secretを、.envファイルに記述し、環境変数にしておきます。
また、Node.jsでは.envファイルを読み込むためには、dotenvというパッケージが必要です。このパッケージを利用するため、先頭に以下の記述を追加します。

require("dotenv").config();

認証部分は、同じコードで問題ないのですが、ツイート実行部分のコードが異なります。
AWS Lambdaで利用するためにexportsしていましたが、ローカルでは不要です。
constを使って関数を定義して実行するようにしています。

const handler = () => {
    const date = new Date().toLocaleString('ja-JP');
    const text = '今日もお疲れ様でした〜😆'
    const tweetText = { status: `${text}\r\n${date}` }

    client.post('statuses/update', tweetText, (error, tweet, response) => {
        if (error) throw error;
        console.log(tweet);
        console.log(response);
    });
}

handler();

ローカル実行時のコード全体は、以下のようになります。

const Twitter = require('twitter');
require("dotenv").config(); // ローカル実行時に必要。

// 認証
const client = new Twitter({
    consumer_key: process.env.CONSUMER_KEY,
    consumer_secret: process.env.CONSUMER_SECRET,
    access_token_key: process.env.ACCESS_TOKEN_KEY,
    access_token_secret: process.env.ACCESS_TOKEN_SECRET,
});

// ツイートするための関数
const handler = () => {
    const date = new Date().toLocaleString('ja-JP');
    const text = '今日もお疲れ様でした〜😆'
    const tweetText = { status: `${text}\r\n${date}` }

    client.post('statuses/update', tweetText, (error, tweet, response) => {
        if (error) throw error;
        console.log(tweet);
        console.log(response);
    });
}

// 定義した関数を実行!
handler();

感想

今回は、AWS LambdaとAmazon EventBridgeを利用して、定期的に特定の言葉をツイートするBot開発に挑戦してみました!
普段は、Reactを使って開発をしていることが多いのですが、Node.jsを利用している場合には、.envファイルを読み込むために別途dotenvというパッケージの導入が必要だということを知らなかったので、勉強になりました。
ちょっと気になるのは、最小単位が「分」であるcronで指定しているからか、指定した時刻の0秒ちょうどではなく、数十秒遅延して実行されている点です。しかも、いつも同じ秒数遅延している訳ではなさそう。秒単位を無視すれば、きちんと時刻通りに実行されています。
まだまだAWSは勉強中ですが、このように実際にサービスを利用しながら勉強してみると、とても楽しいですね〜!

もし、認識の誤り・補足などがあれば、是非、コメントして頂けますと助かります〜!

お読みくださり、ありがとうございました!!

参考資料

お役立ち Twitter Bot を作りながら学ぶ AWS ドリル ~第 1 回 おはよう Bot 編
npm twitter
node-twitter Examples
AWS Lambdaとは
Lambda デプロイパッケージ
Amazon EventBridgeとは
cron LPI-Japan

GitHubで編集を提案

Discussion