前回:Lambdaでお手軽サーバーレス入門(API Gatewayデプロイ編)
今回は別のトリガー、CloudWatch Eventsについて試してみます。
今回やりたいこと
- 毎時5分(7時〜19時)に起動する
7:05, 8:05, 9:05, ..., 19:05 - 天気予報を外部サービスから取得
- 何かしらの方法で知りたい
イベントソースは2種類
Event Pattern
例では、EC2のすべてのインスタンスが起動状態(running)になったとき、を指定しています。
このように、数あるAWSのサービスのイベントをトリガーにできます。
Schedule
○分毎、○時間毎、のような指定方法や、Cronパターンを指定しての細かい設定も可能な、定期的なトリガーです。
今回は、Scheduleを使ってみます。
天気予報を知りたい
いろいろAPIはありますが、今回は私が今住んでいるホーチミンシティの天気を取りたかったので、 OpenWeatherMapのAPIを使ってみます。
API登録
今回はフリーアカウントで十分なので、こちらのページから、登録していきました。
APIは、JSONでこのように返ってきます。
{
"coord": {
"lon": 106.7,
"lat": 10.78
},
"weather": [
{
"id": 802,
"main": "Clouds",
"description": "scattered clouds",
"icon": "03n"
}
],
"base": "stations",
"main": {
"temp": 28,
"pressure": 1008,
"humidity": 83,
"temp_min": 28,
"temp_max": 28
},
"visibility": 10000,
"wind": {
"speed": 2.1,
"deg": 250
},
"clouds": {
"all": 40
},
"dt": 1538314200,
"sys": {
"type": 1,
"id": 7985,
"message": 0.0058,
"country": "VN",
"sunrise": 1538260921,
"sunset": 1538304244
},
"id": 1566083,
"name": "Ho Chi Minh City",
"cod": 200
}
ソースコード
では、Pythonで呼び出してみます。
import os
import json
from urllib.parse import urlencode
from urllib.request import urlopen
from datetime import datetime
API_ID = os.getenv('OWM_API_ID')
DATETIME_FORMAT = '%Y-%m-%d %H:%M:%S'
def lambda_handler(event: dict, context):
if not API_ID:
print('ERROR: No API ID')
return
# get whether information from OpenWeatherMap
url = 'https://api.openweathermap.org/data/2.5/weather?{}'.format(urlencode({
'q': 'Ho Chi Minh City,VN',
'units': 'metric',
'appid': API_ID
}))
with urlopen(url) as f:
raw_data = json.loads(f.read().decode('utf-8'))
print('Location: {}, {}'.format(raw_data['name'], raw_data['sys']['country']))
print('Time: {}'.format(datetime.fromtimestamp(raw_data['dt']).strftime(DATETIME_FORMAT)))
print('Weather: {}, {}'.format(raw_data['weather'][0]['main'], raw_data['weather'][0]['description']))
print('Temperature: {}℃'.format(raw_data['main']['temp']))
print('Pressure: {:,}hPa'.format(raw_data['main']['pressure']))
print('Humidity: {}%'.format(raw_data['main']['humidity']))
このような出力結果を期待します。
Location: Ho Chi Minh City, VN
Time: 2018-09-30 20:30:00
Weather: Clouds, scattered clouds
Temperature: 28℃
Pressure: 1,008hPa
Humidity: 83%
なお、Lambda関数を作成時、環境変数に以下を設定してください。
- OWM_API_ID
OpenWeatherMapで取得したAPI ID
実行時間は、余裕を見て1分としました。
CloudWatchのイベントを設定する
CloudWatch management console
左ツリーのEvents→Rulesを押して、画面のCreate Ruleをクリックします。
ソースの設定
Scheduleを選んだあと、Cron expressionを選ぶと、Cron式を入力できます。
スペース区切りで、6つの指定が必要です。
分 時 日 月 曜日 年
- 分
- 値:0-59
- ワイルドカード
-
,
カンマ(複数指定) -
-
ハイフン(範囲指定) -
*
アスタリスク(全指定) -
/
スラッシュ(増分指定)
-
- 時
- 値:0-23
- ワイルドカード
-
,
カンマ(複数指定) -
-
ハイフン(範囲指定) -
*
アスタリスク(全指定) -
/
スラッシュ(増分指定)
-
- 日
- 値:1-31
- ワイルドカード
-
,
カンマ(複数指定) -
-
ハイフン(範囲指定) -
?
クエスチョン(任意値指定) -
*
アスタリスク(全指定) -
/
スラッシュ(増分指定) -
L
(最終日指定) -
W
(平日指定)
-
- 月
- 値:1-12 または JUN-DEC
- ワイルドカード
-
,
カンマ(複数指定) -
-
ハイフン(範囲指定) -
*
アスタリスク(全指定) -
/
スラッシュ(増分指定)
-
- 曜日
- 値:1-7 または SUN-SAT
- ワイルドカード
-
,
カンマ(複数指定) -
-
ハイフン(範囲指定) -
?
クエスチョン(任意値指定) -
L
(最終日指定) -
#
シャープ(何週目指定)
-
- 年
- 値:1970-2199
- ワイルドカード
-
,
カンマ(複数指定) -
-
ハイフン(範囲指定) -
*
アスタリスク(全指定) -
/
スラッシュ(増分指定)
-
UTCで指定しますので注意してください
ここでは、インドシナ時間(ICT, UTC+7)で7:05〜19:05まで、毎日実行したいので、 5 0-12 * * ? *
と指定しました。
日本時間(JST, UTC+9)だと、5 2-14 * * ? *
となりますね。
テキストボックスの下には、直近のトリガー10個が表示されるので確認にも使えます。
ターゲットの設定
右側はターゲットの設定で、何を実行するかを指定します。
ここでは、先程作ったLambdaを指定します。
※Lambda以外にもいろいろ実行できます。
右下のConfigure detailsをクリックします。
名前と説明、Stateを選択します。
StateのEnabledにチェックを入れておくと、すぐに有効になります。
しばらく実行したくない場合は、このチェックを外します。
あとから有効・無効は切り替えられます。
すべて終わったら、Create ruleをクリックします。
作成されると、一覧に表示されます。
ここで有効・無効を切り替えたい場合は、緑アイコン(無効時はグレーアイコン)左にあるラジオボタンをチェックして、Actions→Disable(Enable)を選びます。
ログを見てみる
さて翌日、きちんと動いたかを見てみます。
きちんとLog Groupができています。
Log Groupは、/aws/lambda/関数名
となっています。
ここをクリックすると、
Log Streamを確認できます。
Log Streamが新しくなる理由は、関数を更新したり、一定時間以上空いた場合になります(と思います、自信ないです)。
ストリーム名をクリックすると、
無事に、希望通りの出力があります!
次回予告
今回、ログに出力しただけなので、わざわざ見に行かないといけないです。
面倒くさいので、Twitterに通知を飛ばしてみます。
素でTwitter APIを叩いてもいいのですが、ここは世の中便利なライブラリがたくさんあるので、Lambdaでどのようにライブラリを使うのか、をメインに、Twitterでこの情報を通知できるようにします。