(1)使用 Serverless 讓 AWS SQS 幫你發送 LINE Notify

NiJia Lin
10 min readAug 24, 2019

--

0x00 前言

以前自己在架伺服器的時候,提到訊息佇列不外乎都是 RabbitMQ 或是 Kafka,只是現在 AWS、GCP 這類的雲端平台都越來越火紅了,手動按一下服務就建好了(信用卡也在哭泣),省去很多建立服務的時間,只是說一般時候根本找不到項目練習😓,剛好最近在複習 LINE Notfiy,就趁這個機會順便練習並記錄一下✌️

0x01 你需要先了解…

當 Http requests 非常大量到一定程度,database 已經跟不上處理的速度,尤其是 relational database,這時就需要 queue來緩衝;所以社群網站像Facebook or LinkedIn都使用大量的 message queue and cache
- Leonard Lee

SQS就是 managed queue service,主要就是async, central messaging (對相對應的程式來說,通常處理api的會有多個instances同時存在,像是auto-scaling),像是fb通知、寄送email認證信這種不用即時處理的情況,只要給訊息給queue讓其他服務或程式去處理,可以把原本的邏輯簡化(以及責任區分),甚至些事件是預期同時會有多個listener會需要處理的情況,在一個api裡面去處理這些會讓邏輯變很複雜/不好維護。
- Bill Chung

還有就是如果負責處理 request 的 host 有問題,message queue 可以用來短暫儲存還未被處理的requests 使他們不至於丟失,直到 host 回復正常或是換了一個好的host 後,message queue 裡面的的requests就可以繼續被處理
- 盧元駿

[ Updated ] 謝謝 python taiwan 的兩位大大熱情補充!

今天在需要發個請求去呼叫 LINE API(或是其他服務的 API),都可能會碰到圖片,圖片不管他怎麼壓縮,終究還是比文字肥,在數量多的情況下可能就會發現 API 罷工(就會像被斷詠唱一樣)。雖然平常使用可能不會這麼平凡呼叫,但若在商業用途上使用者多的時候一次呼叫就會有一大筆,這時候用 Queue 讓他們排隊一個一個來就在適合不過了🎉,本文就用 LINE Notify 當作範例來實作讓 SQS 幫忙發送。

服務被大量請求 K 到的時候就是這樣…

0x02 為什麼選擇 AWS SQS

因為我公司都在用啊(被拖走)

Amazon Simple Queue Service (SQS) 是全受管訊息佇列服務,可讓您分離和擴展微型服務、分散式系統及無伺服器應用程式。SQS 可免除與管理和操作訊息導向中介軟體相關的複雜性及開銷,也可讓開發人員專注在與眾不同的工作上。您可以使用 SQS 在軟體元件之間傳送、存放和接收不限數量的訊息,不會遺失訊息或需要其他服務可用。使用 AWS 主控台、命令列界面或自選的 SDK 以及三個簡單的命令,即可在幾分鐘內開始使用 SQS。(參考 AWS)

SQS 有在免費方案裡面,只要一個月別高於 100 萬個請求就不會被收錢啦💪

0x03 建立專案

首先先透過我之前做的 repo 來做基底,用它來改改~

$ serverless install --url https://github.com/louis70109/aws-line-echo-bot -n <YOUR_FILE_NAME>
$ cd <YOUR_FILE_NAME>/
Clone 下來應該會是長這樣

0x04 建立 Consumer lambda

還不知道怎麼新增 LINE Notify 的朋友可以參考 我的簡報 並搭配 LINE Notify API 服用

LINE Notify 認證機制

這邊假設你已經拿到了 Notify Token (需要搭配 Bearer) 了,接著將 handler.py 的程式改為以下

import json
import requests


def webhook(event, context):
print(event['body'])
headers = {
'Authorization': 'Bearer YOUR_NOTIFY_KEY',
'Content-Type': 'application/x-www-form-urlencoded'
}
r = requests.post('https://notify-api.line.me/api/notify',
headers=headers,
data={'message': event['body']})

然後修改一下 serverless.yml,先把這幾行刪掉(因為不是做 API)

events:
- http:
path: /webhook
method: POST

接著執行以下指令做本地端測試 (這邊的 -f 後面的名字若要修改的話從 serverless.yml -> functions 下面去修改即可)

sls invoke local -f line_bot --data '{"body": "Hell world QAQ"}'

到了這裡你的 Notify 第一步串接就成功囉!

serverless CLI test local example

0x05 建立 SQS

接著就要開始引入 SQS 嚕,首先到 AWS 上的 SQS 頁面,如下

進到首頁之後選擇 Get Started Now
打上 Queue name 並選擇左邊後,按下按鈕建立
接下來就會看到你的 SNS 基本資訊囉!

0x06 修改 Consumer lambda

建立完 SQS 之後呢,我們需要先改一下原本 handler.py 的程式碼

import json
import requests
def webhook(event, context):
print(event)
body = json.loads(event['Records'][0]['body'])
print(body)
headers = {
'Authorization': body['token'],
'Content-Type': 'application/x-www-form-urlencoded'
}
r = requests.post('https://notify-api.line.me/api/notify',
headers=headers,
data={'message': body['message']})
print(r)

並在 requirements.txt 裡加入 requests==2.22.0

部署的時候 Lambda才會知道要安裝套件喔!

接下來就是下 sls deploy 進行部署,結束應該會看到下面這張圖片的內容:

deploy 成功!

註記

Deploy 時可能會有類似的錯誤訊息需要你注意一下服務設定的位置哦

An error occurred: LineUnderscorebotEventSourceMappingSQSLINEnotifyqueue - Event source region must match Lambda region us-east-1 (Service: AWSLambda; Status Code: 400; Error Code: InvalidParameterValueException;

0x07 建立發送端

接著我們建立一個測試的檔案 (send.py),透過 boto3 來幫忙送訊息到 AWS SQS 🧚‍♀️

import json
import boto3
import sys
cli = boto3.client("sqs", region_name='us-east-1')def send_message(url, attr, body, delay=0):
cli.send_message(
QueueUrl=url,
DelaySeconds=0,
MessageAttributes=attr,
MessageBody=body,
)
output = {
'message': sys.argv[1],
'token': 'Bearer YOUR_NOTIFY_TOKEN'
}
#執行函式
send_message(
url="https://sqs.us-east-1.amazonaws.com/901588721449/LINE_notify_consumer",
attr={},
body=json.dumps(output)
)

url 裡的內容要參考你建立出來 SQS 資訊裡的 URL 哦!

python sender.py "Hello world"
測試發送

如此一來就成功了(撒花🎉),代表寫的腳本有送進 SQS 並 trigger lambda 幫忙發送訊息到 LINE Notify 上面~

上述的 code 同步到 Github 上囉!

0x08 結論

前一陣子在公司學到的新技能,不過一直想不到有什麼好的例子去做紀錄,剛好最近重新複習了 LINE Notify,索性就乾脆寫在一起以後需要回來考古的時候有個依據,這次應用就到這邊,謝謝您的收看,我們下此見!

怎麼好像 youtube 看太多?

--

--