0%

簡介

繼上一篇 warm-up 機制之後來了解一下如何使用 AWS 的 CDN 服務 - cloudfont,CDN 顧名思義就是要讓使用者可以到最接近的主機上去拉到對應的資料,透過撒點的方式讓主機去挑選離自己近的服務據點,藉此加速服務。

像我之前部署在 ohio,想想光網路的時間 + Cold start 的時間就已經去了一大半,即便我們有熱開機,服務沒有 Timeout 我該慶幸了,既然如此就不得不認識一下 CDN 服務,而 AWS 的 CDN 服務就是 cloudfont 啦!

只是說原本的 domain 已經有 SSL 了,但是代理沒有這個東西,所以我們要 ban 出一個 Certificate,那在在建立 cloudfont 以前需要先到 Certificate Manager,接著會用圖片帶大家一步一步做

開始之前

我已經有先在 Route53 註冊了一個 nijialin.com 的 domain,.com大概 10 美金左右,若是有在其他地方註冊域名的話要找一下相關文章把它導進 Route53 哦!

註冊 Certificate

  • 先來到 Certificate Manager 頁面,按下左下角的這個

  • 接著就直接按右下角啦,但是要確定是不是 public

  • 這裡輸入你在 route53 註冊的 domain,這邊我是輸入 *.nijialin.com

  • 到第四部之後就會看到申請的 SSL Pending

  • 最後回首頁之後就會看到 SSL 簽證正在送簽中

最後就等他完成嚕!將將

接著我們到 API Gateway 找到左邊的 Custom Domain Name,我們要來建立屬於這個 API 的 Domain 了

按下藍色的按鈕之後,輸入Domain name以及選擇剛剛註冊的 Certificate 後按下 Save

他就會開始初始化剛剛的設定,這邊大概需要等 15 分鐘左右

在此同時我們就去新增專案裡的套件 Domain-Manager

1
npm install serverless-domain-manager --save-dev

並且在plugin下加入套件

1
2
plugins:
- serverless-domain-manager

custom底下加入

1
2
3
4
5
6
7
custom:
domainName:
default:
domainName: line.nijialin.com
certificateName: "*.nijialin.com"
createRoute53Record: true
endpointType: edge

等待前面初始化成功之後部署這個專案sls deploy之後就會看到剛剛註冊的域名啟動囉!

結論

在建立 Certificate 那邊倒沒什麼問題,畢竟需要一個 SSL,只是到了建立 domain 這邊遇到了很怪的問題,一般來說使用 serverless 框架來跑的話只要照的文件裡說的 serverless create_domain就會幫忙註冊,而且可以依照自己開發環境去自動設定,在公司的專案中這樣使用是沒問題的,在是在寫這篇文章時卻只能使用以上的方法來替代使用,雖然結果是一樣的,但是用起來實在是很不符合邏輯,google 也沒找到類似的問題,或許這個問題還要多實測幾次才夠…😭

前言

人品爆發的下半年有幸被選為 LINE API Expert,謝謝過程中給我指點、意見還有每位來參加每個 chatbot TW 活動的朋友,你們支持讓我可以更努力去辦各種活動,社團裡歡迎大家踴躍提點子討論,抑或是來參加小聚跟大家互相交流,台北台中都有小聚哦!若有不清楚的地方歡迎詢問😃
Chatbot Developers Taiwan:https://www.facebook.com/groups/chatbot.tw

迎新

在 welcome party 中身為 Rookie of LINE API Expert 一定是要被每一位大神輪流 “熱情關照” 一波🤣,想想之前在開發時還在看卡米狗 卡卡米 的 IT 30 鐵人賽、寫 golang 看著 Evan Lin 的部落格、看保哥 Will Huang 在議程中各種秀高速開發技能 … 等等的,沒有到偶像們就直接坐在旁邊,看著看著我就快不行了😝。跟大神們聊完覺得自己做的事還只是冰山一角,看著大家都那麼有影響力下還是這麼努力向前進,做為菜鳥的我當然不能就這樣滿足!繼續抱著大神們的腿前進。(喂!放開自己走啊!)

成為 LAE 後的第一場開發者日

緊接著第一場大型活動就是參加 LINE 的年度大會 — LINE Developer Day,過往都只能看著前輩們分享文章在電腦前面乾過癮,看著大家可以在國際間跟各路的開發者交流,這一直是我很羨慕的事情之一。但是!現在終於有機會以 LAE 的身分出發啦(媽我在這)!聽說去年有 60 場各種主題的座談會,而今年 LINE 主要會以推廣 人工智慧 為主軸,並且搭配其他在 LINE 中重要的技術形成了這次的 developer day,也開始漸漸露出在新聞版面了,看起來想拓展的企圖心也越來越強了🚀
以下是其他 LAE 以及社群創始人 Clement Tang 在 2018 年參加 LINE Dev Day 的文章分享

2019 的 Dev Day 資訊出來囉,
活動時間: 2019/11/20、21, 10:00~21:00 (日本時間)
活動地點:東京台場日航大酒店Grand Nikko Tokyo Daiba (2–6–1 Daiba, Minato-ku, Tokyo)
活動入場費用:免費
參加方式:繳交報名表、預先報名

活動則環繞在開發工程(Engineering)以及產品開發(Production)上

「LINE DEVELOPER DAY」開發者大會將於11/20、21東京登場 | T客邦

屆時我會分享文章出來,還請各位多多關注😀

結論

說了這麼多,還不去申請一波 LINE API Expert?讓自己的努力有個機會被 LINE 看見:
LINE developers community | Expert Request
或是你還不清楚要怎麼開始第一步,來小聚跟我們聊聊吧,社群的每位大大都很熱心跟各位分享,千萬別錯過這些機會哦!
Chatb13ts meetup 聊天機器人小聚 #13 @ 台北商業大學
▎活動型態 Chatbots meetup 社群台北、台中皆有一個月一次的定期聚會,致力於提供並討論聊天機器人的相關應用,每回小聚將安排講者主題分享、新知討論,環繞 Chatbot。

前言

本篇會介紹 npm 套件庫裡的 Serverless-plugin-warmup,裡面介紹了很多參數可以使用,以下會簡介如何引入它。

實作

透過npm來安裝套件

1
npm install --save-dev serverless-plugin-warmup

serverless.ymlplugin加入套件

1
2
plugins:
- serverless-plugin-warmup

custom加入warm up的設定參數

1
2
3
4
5
6
7
8
9
custom:
warmup:
enabled: true
cleanFolder: false
memorySize: 128
name: "LINE-warmup-pop"
events:
- schedule: "cron(0/5 0-12 ? * MON-FRI *)"
timeout: 10

.gitignore加入以下兩個_warmup/以及.requirements.zip,他在部署前建立一個_warp的資料夾並放一個 Lambda 來打已建立的 api 以及 Lambda 們,部署後會建立.requirements.zip,所以這邊就加入這兩行來防止被 git 推上去。

或許會有疑問不是cleanFolder設定 true 就可以,這邊我自己實測時在部署會因為 Size 過大而無法上傳,把這參數設定掉他才會乖乖的上傳成功,但這部分有待驗證。

加入 decorator

這邊我在lib/下新增一個decorator.py,加入以下的 code

1
2
3
4
5
6
7
8
9
10
11
12
from functools import wraps
from logging import Logger

def lambda_warm_up(func):
@wraps(func)
def wrapper(*args, **kwargs):
source = args[0].get('source')
if (source == 'serverless-plugin-warmup'):
Logger.info('WarmUp - Lambda is warm!')
return {}
return func(*args, **kwargs)
return wrapper

主要功能是透過 python decorator 的特性讓我們在 function 之前用個前綴符號就可以引用它,很像 po 文在 tag 別人一樣 🤣
warm-up 建立的 Lambda 會固定對其他的 Lambda 打serverless-plugin-warmup的字串,這邊就寫個判斷式判斷掉後直接 return

你以為這樣就結束了?還有 IAM role 的問題呢,詳細問題已不可考,想試看看的可以把 IAM 拔掉再部署一次,問題就會出現了,以下為設定檔:

1
2
3
4
5
6
7
8
9
10
11
iamRoleStatements:
- Effect: "Allow"
Action:
- "lambda:InvokeFunction"
Resource:
- Fn::Join:
- ":"
- - arn:aws:lambda
- Ref: AWS::Region
- Ref: AWS::AccountId
- function:*

如果你的目錄結構跟我一樣,或是跟到今天的實作,加入以下的 code,這邊主要是告訴你的 Lambda 要在每次的 warm-up 字串來的時候呼叫這個 decorator 來幫忙處理一下

1
2
3
4
5
from lib.decorator import lambda_warm_up

@lambda_warm_up
def xxx():
pass

我的 Lambda 都加了,那原本的 flask 建立的 api 我要加在哪?

看看這個網址,serverless-wsgi 在實作的時候已經有考慮到這件事了,所以 api 這邊就不用管他,他自己會去把它處理掉!

結論

Warm-up 的機制就是透過建立一個 Lambda 來打一個 flag 到其他 Lambda 來他們別進入睡眠模式,但總是會有人考慮費用的問題,可以參考下圖,若是你建立了一個簡單的服務然後上線了,AWS 給你了一百萬個請求的量,我覺得一個月的請求可以到 100 萬應該是服務有點規模的情況,一個月能到這個量相信你也有一定的能力養它 🤣,爾後每一百萬個請求才六塊台幣,可能比 GCP 還貴,但其實以我來說這樣已經很夠用,而且還扛得住

參考

serverless-wsgi Warm-up code
Serverless-plugin-warmup

前言

以下就為大家帶來簡單的實作以及如何去使用它。

實作

views/下新增一個liff_test.html並加入以下內容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
<html>
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
/>
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.js"></script>
<script src="https://d.line-scdn.net/liff/1.0/sdk.js"></script>
<script>
function initializeApp(data) {
$("#userid").val(data.context.userId);
}

$(function() {
liff.init(function(data) {
initializeApp(data);
});

$("#ButtonGetProfile").click(function() {
liff.getProfile().then(profile => {
$("#UserInfo").val(profile.displayName);
alert("done");
});
});

$("#ButtonSendMsg").click(function() {
liff
.sendMessages([
{
type: "text",
text: $("#msg").val()
}
])
.then(() => {
alert("done");
liff.closeWindow(); // 關掉頁面
});
});
});
</script>
</head>
<body>
<button class="liff_btn">Get user profile</button>
<label>user id:</label>
<input class="form-control" type="text" id="userid" /> <br />
<button class="btn btn-primary" id="ButtonGetProfile">Get Profile</button>
<input class="form-control" type="text" id="UserInfo" /><br />
<label>要傳送的訊息:</label>
<input class="form-control" type="text" id="msg" value="測試" /><br />
<button class="btn btn-primary" id="ButtonSendMsg">要傳送的訊息</button>
</body>
</html>

以上參考來自董老師的部落格

詳細的 LIFF API 文件可以參考

接下來按著之前做過的一樣把這個檔案送到S3裡,接著它的網址複製起來

接著來去之前建立機器人的開發者頁面裡按下最右邊的LIFF

按下去之後呢,再來按下add

跑出這個頁面後,Name好辨認為主、Size選擇滿版(Full)、Endpoint URL就把剛剛複製起來的 S3 網址放進去後按Confirm

大概內容會長得像這樣

建立成功後往下滑會看到 LINE 給你一個屬於他們的網址,接著可以把它貼到你的機器人上(或者任何聊天室)

點下去之後就會看到來自 LIFF 的 Webview 囉!

接下來就可以開始玩裡面的功能了 🤣

結論

LIFF 整合的功能讓開發者在 Bot 裡不好實現的功能透過 Webview 的方式讓使用者可以到頁面上做邏輯處理,透過兩種的結合讓整體的應用就有更多的變化,這邊若要給使用者個話就把 line://xxxoxx 製作成 flex message 或者乾脆傳給使用者,引導他點選,如此就能讓使用者到自己設計的頁面上了。

這邊額外補充一點,有看到程式碼裡面可以拉到Query string嗎?事實上可以透過Query string讓使用者帶些參數來做更多的判斷,像是卡米哥做的Kamiliff就是讓使用者在點選後判斷這個 LIFF 的 Size,在導去對應的路由去做處理,這樣子使用者在建立 LIFF 的時候就不用一個頁面弄一個,否則這樣在 dev 轉 prod 的時候應該會弄到很生氣 🤣。

介紹

LIFF (LINE Front-end Framework)顧名思義就是 LINE 開發在 LINE 這個通訊軟體裡面的 Web view(好饒舌),他是一個很精簡的內建瀏覽器,主要是能夠讓開發者可以使用 HTML & Javascript 可以去處理一些在 bot 不好實現的功能,也讓開發者可以透過使用 JS SDK 去拉使用者的資訊,藉此可以做出更多種的應用。

網址的樣式都像是這樣line://app/ZZZZZ-AAAAAAA,透過 deep link 的方法讓 LINE 本身可以認得這個藉此去導向設定對應的網站,畢竟做平台的公司內部要互相溝通也是,就透過這種方法去讓不同部門的工程師可以互相使用好像也是不錯(?)

它也可以搭配在之前做的 LINE 服務上,Notify、Message api 上都可以串上去搭配不同種應用,而這個簡易的 Web view 有下面三種的顯示格式可以使用,開發者可以搭配不同應用場景去做搭配。

一開始都只能使用 curl 來增加項目,使用方法可以參考這篇,現在可以直接在 LINE Developer 頁面線上新增,像下圖片在這個頁面就可以新增了

1
2
3
4
5
6
7
8
9
10
curl -X POST \
-H "Authorization: Bearer YOUR_CHANNEL_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"view": {
"type": "LIFF_SIZE",
"url": "URL_OF_YOUR_APPLICATION"
}
}' \
https://api.line.me/liff/v1/apps

這邊推薦一個 kamiliff,卡米哥就用一個路由帶著 query string 來判斷,再轉打去其他 controller,如此一來就不需要為了每個頁面去獨立建立 LIFF,如此一來測試跟上線都很好管理,推薦大家去參考卡米哥的 kamiliff 的實作方法~

這個功能最大的好處就是可以在 LINE 裡面就可以直接用,若是把使用者導出頁面基本上轉換率以及使用者體驗一定會變很差,所以若是有在開發 LINE Bot 的話很推薦使用這個。

結論

以前我曾嘗試過使用 LIFF 使用 websocket 去跟 MQTT 溝通( IoT 裝置常常使用的通訊格式),只是他的 websocket 似乎有開,但是總是沒有收到數值,這部分實作也是年初時使用,現在這時候就不知道能不能用了 🤣,若不行就期待哪天他能提供出這個服務了~

參考

LIFF overview

前言

在第 Day 13 Python SDK 試玩的時候使用過 get_profile,當時使用時就是在每次訊息來的時候才去 SQL 儲存使用者資訊,若只是單純想要使用者資訊的話這樣用好像有點多餘 😓,以下就帶各位簡單的實作。

實作

我們要將上篇的前端頁面(line_login_auth.html)改造一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>LINE Login</title>
</head>
<body></body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.js"></script>
<script>
$.ajax({
url: "https://YOUR_SLS_DOMAIN.us-east-1.amazonaws.com/dev/line/auth",
method: "POST",
success: function(data) {
window.location.replace(data.result);
}
});
</script>
</html>

這邊我將 button 的 onclick 事件以及 button 本身移除掉,目的是要讓使用者一到這個頁面之後就直接透過 AJAX call api

到了這裡應該有感應到什麼了吧!接著就是把這個 html 檔的 S3 路徑網址使用 QR code 包起來,讓他看起來像是 LINE bot 的 QR code

到了這邊基本上已經快完成了,參考 LINE 的好友說明或下圖

接著到機器人的開發者頁面,並且往下滑會看到自己機器人的 QR code 以及 Bot 的 ID,把他複製下來並製作機器人的加好友網址

像是這樣子

1
https://line.me/R/@1234

接著到 controller/line_login_controller.pydef get(self)最後一行,原本我們這邊做的是回傳 JSON

1
2
if dt:
return {'result': dt}, 200

改用

1
2
3
from flask import redirect
if dt:
return redirect("https://line.me/R/ti/p//@127ojvgz", code=302)

如此一來在登入驗證完之後就會把使用者導向到加好友的頁面,在手機上若已經加過好友則會直接導到機器人對話窗上,如此一來就可以讓使用者在加入好友的同時也綁定完帳號,在未來使用的時候 api 這邊也比較好控管使用者的權限問題。

結論

像是我自己做的健身記錄機器人,就是以這個方法下去實作,有聽過一些朋友跟我反應這樣的方法多此一舉,但我認為若是有網頁的話也是套用 LINE SSO 來實作,就可以讓兩個入口去統一,在狀態流上就能比較好控制了。

前言

現在有規模的平台提供商基本上都會提供 Single Sign On (SSO)的登入機制,藉由他們的平台讓一般小網站可以讓使用者免密碼登入,雖然有很多種 Oauth2 的套件,不過我還是喜歡自己打 🤣,下面就開始嚕!

實作

views/建立一個line_login_auth.html,填入以下內容,主要是實作一個按鈕並透過 javascript 來互叫 api 並導向到 LINE 頁面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>LINE Login</title>
</head>
<body>
<button class="auth" onclick="auth()">LINE LOGIN</button>
</body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.js"></script>
<script>
function auth() {
$.ajax({
url: 'https://YOUR_SERVERLESS_DOMAIN.amazonaws.com/dev/line/auth',
method: 'POST',
success: function(data) {
window.location.replace(data.result);
},
});
}
</script>
</html>

接著我們在.env加入 LINE Login 的環境變數並輸入對應的參數

1
2
3
LINE_LOGIN_CLIENT_ID=
LINE_LOGIN_SECRET=
LINE_LOGIN_URI=https://YOUR_SERVERLESS_DOMAIN.amazonaws.com/dev/line/auth

最後就是我們最重要的部分了,實作 GET a& POST 的 api,這邊我先從 POST 講起,這邊主要是把環境變數組在網址中回傳給前端,這邊需要注意的是state他是在回傳回來的 JWT 需要解碼時所使用的,這邊我簡單打個字串,然而實際上會隨機產個變數,確保解碼的安全。

GET 則是負責處理從 LINE 回來的參數們,這邊我只用回傳回來的stateid_token解開,拿到裡面的使用者的參數,後續可以參照應用把資訊存下來,放入 session 並告知前端已登入。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
from flask import request
from flask_restful import Resource
import requests
import webbrowser
import os
import jwt
import json


class LineLoginController(Resource):
def get(self):
r = requests.post(
"https://api.line.me/oauth2/v2.1/token",
data={
"grant_type": "authorization_code",
"code": request.args.get('CODE'),
"redirect_uri": os.environ.get('LINE_LOGIN_URI'),
"client_id": os.environ.get('LINE_LOGIN_CLIENT_ID'),
"client_secret": os.environ.get('LINE_LOGIN_SECRET'),
}, headers={"Content-Type": "application/x-www-form-urlencoded"})
payload = json.loads(r.text)
print(payload)
token = payload.get("id_token")
if token is None:
return {'result': payload['error_description']}, 400

state = request.args.get('state')
token = token.encode()
dt = jwt.decode(token, state, None, algorithms=['HS256'])
if dt:
return {'result': dt}, 200

def post(self):
r_uri = os.environ.get("LINE_LOGIN_URI")
client = os.environ.get("LINE_LOGIN_CLIENT_ID")
state = "nostate" # it will be random value
uri = f"https://access.line.me/oauth2/v2.1/authorize?response_type=code&client_id={client}&redirect_uri={r_uri}&scope=profile%20openid%20email&state={state}"
return {'result': uri}

JWT 解開的參數如下,sub就是 LINE 的唯一值 ID,一般拿到這個就可以知道是來自 LINE 的使用者了。

1
2
3
4
5
6
7
8
9
10
11
12
13
{
"result": {
"iss": "https://access.line.me",
"sub": "Ud6ab866a67xxxxxxxxb12b0baffb8ac",
"aud": "1622939248",
"exp": 1569925548,
"iat": 1569921948,
"amr": ["linesso"],
"name": "NiJia Lin",
"picture": "https://profile.line-scdn.net/0hKvTocMuLFFlpFj9HpKdrDlVTGjxxxxxxxxx1YHACMOPRtEHmkWJVIKUyUJNkQWGT0X",
"email": "loxxxxx09@gmail.com"
}
}

最後別忘了要在api.py加入路由才會被導出去ㄛ

1
2
from controller.line_login_controller import LineLoginController
api.add_resource(LineLoginController, '/line/auth')

結論

在實作的時候不知道為什麼一直不能讓 python 去幫我把用戶導去 LINE 認證的頁面,我記得之前寫 Ruby 可以啊(?),最後只好讓前端去幫我把使用者導出去,這邊就帶大家做到這嚕!

前言

上篇介紹了好多了,這邊就不廢話了,直接就帶大家申請一個 LINE Login 的服務。

實作

首先到自己的開發者頁面按+,並選擇最左邊的選項

接著輸入App name(服務名稱)、App description(服務簡介),因為我們是實作 API ,所以選擇Use WEB的選項,接著再輸入email

把該填的填完之後按下送出就會看到有一個新的服務嚕!

點進去後往下滑,可以看到有個 link to this channel 的選項,這邊選擇一開始建立的那隻機器人,綁定之後就變它的形狀啦(?)

接著再往下會看到 Email 的狀態是 Unapplied,然後按下右邊的Submit

會看到這樣子的一個框框,把兩個框框打勾並選擇一張圖片上傳,這部分就算是申請帳號下面的同意服務條款一樣,圖片就上傳自己希望當使用者到你頁面的時候想看到的圖片 🤣,送出之後就會看到狀態改成 Applied

結論

很多時候實作對我們來說已經不是什麼問題了,重點是在找不到服務要怎麼去申請 😓,這篇也算是記錄一下申請的步驟細節,接下來會實作個簡單的認證頁面以及 API,打完收工嚕!

前言

LINE 中文版也上線啦 URL
去某些網站登入你可能會有像下面這樣

或者是你有玩過 LINE Rangers (怎麼感覺我好老),就會看到他們登入畫面有個登入鈕,按下去按確認後就登入,使用者不用輸入帳號密碼。

這個機制被稱為 SSO (single sign-on),它是透過 OAuth2 的機制來做認證,因為不儲存密碼除了可以降低儲存第三方網站的風險,以及使用者不需要記憶各種不同的密碼所帶來困擾,像是 Facebook、Google、LINE…都有相關的機制可以串連 SSO 的服務。

以下會介紹 LINE Login 的流程。

流程

這裡我使用 LINE Login

  1. 服務要引導使用者到 LINE 認證頁面並帶著必填的欄位。
  2. LINE 會在瀏覽器上打開認證頁面,使用者必須按下同意才會進行認證。
  3. LINE 會透過設定過的 redirect_uri 還給你一個 authorization code 以及 state 在 Query string 上。
  4. 你的服務需要將 authorization code 打到https://api.line.me/oauth2/v2.1/token
  5. LINE 確認完之後就會送你一個 access token 嚕!

    可以拿透過 social API 去拿到相關資訊

結論

下一篇再帶著大家申請一個 LINE Login 的服務並建立一個簡單的註冊頁面~

參考

OAuth wiki
LINE overview
LINE 中文文件

前言

過往寫了這麼多的 api,總是會有特定的功能會需要輪詢資料庫或是監聽某些事件,以前還要到弄個虛擬機寫腳本用 crontab,這時候 Lambda 的用處就來啦!不只可以處理 api 的事情,還可以設定排程做事,太舒服啦,以下就來介紹一下~

實作

首先在 consumer 資料夾下line_bot_alert.py,再寫一段需要定時跑的程式,這邊我去抓中央氣象局的資料,大概簡單判斷一下區域以及算出他的範圍:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import json
import requests

def alert_handler(event, context):
air = requests.get(
'http://opendata.epa.gov.tw/webapi/Data/REWIQA/?$orderby=SiteName&$skip=0&$top=1000&format=json')
air_body = json.loads(air.text)
air_status = ["良好", "普通", "對敏感族群不健康", "對所有族群不健康", "非常不健康", "危害", "資料有誤"]
total, count = 0, 0
for fetch in air_body:
if (fetch['County'] == "臺中市" and (fetch['SiteName'] == "西屯" or fetch['SiteName'] == "沙鹿")):
count += 1
if fetch['AQI'] != 0:
total = total + int(fetch['AQI'])
switch = 0
pm = int(total / count)
print(pm)
if pm in range(0, 50):
switch = 0
elif pm in range(51, 100):
switch = 1
elif pm in range(101, 150):
switch = 2
elif pm in range(151, 200):
switch = 3
elif pm in range(201, 250):
switch = 4
elif pm in range(251, 300):
switch = 5
else:
switch = 6
payload = f"\n空氣品質: {air_status[switch]}"
r = requests.post('https://1uv2o723o4.execute-api.us-east-1.amazonaws.com/dev/notify/sqs',
data={'message': payload})
print(r)

serverless.yml的 function 下面加入 Lambda,handler 就是 資料夾/檔案.類別,設定事件(event)排程一分鐘一次

1
2
3
4
5
function:
line_bot_alert:
handler: consumer/line_bot_alert_handler.alert_handler
events:
- schedule: rate(1 minute)

AWS Lambda 有兩種設定排程的方法,rate以及cron,若是比較固定時建議用rate,比較複雜的排程就可以讓cron來,下面兩張圖分別是來自 AWS >


sls deploy部署之後就會看到剛剛做line_bot_alertfunction,他每分鐘都在跑,若玩完之後不想用了可以下sls remove把上面有的東西刪掉嚕!

結論

其實還有很多應用可以實作排程,像是有朋友就用 GCP 的來定時發文 🤣,而且可以把腳本寫得像是 api 一樣,讓整個靈活性都增加了不少,下一篇就帶大家來做 LINE Login 嚕!

參考

AWS document