質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.46%
AWS Lambda

AWS Lambdaは、クラウド上でアプリを実行できるコンピューティングサービス。サーバーのプロビジョニングや管理を要せず複数のイベントに対してコードを実行します。カスタムロジック用いた他AWSサービスの拡張やAWSの規模やパフォーマンスを用いたバックエンドサービスを作成できます。

Node.js

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

Q&A

解決済

1回答

1041閲覧

【Lamda、Node.js】どのようにユーザーの状態管理をするのか(LINE BOT 作成中の疑問)

Yusuke_m25

総合スコア74

AWS Lambda

AWS Lambdaは、クラウド上でアプリを実行できるコンピューティングサービス。サーバーのプロビジョニングや管理を要せず複数のイベントに対してコードを実行します。カスタムロジック用いた他AWSサービスの拡張やAWSの規模やパフォーマンスを用いたバックエンドサービスを作成できます。

Node.js

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

0グッド

0クリップ

投稿2021/12/20 13:44

編集2021/12/21 15:26

AWS Lamda , AWS API Gateway , Node.js といった技術を使って、LINE BOTの作成をしています。
普段はフロントエンドを触っているのですが、バックエンドやAPI、クラウドサーバーの理解を深めるために勉強/趣味の一環としてLINE BOTの作成にトライ中です。

ほぼコピペでオウム返ししてくれるBOTの作成はできました。

この後、例えばですが、
ユーザーが「true」と発言したら、そのユーザーのstatusフラグをtrueにして、
statusフラグがtrueの間、30分おきにBOTからメッセージが送られてくる
ユーザーが「false」と発言したら、そのユーザーのstatusフラグをfalseにする。
といったLINE BOTにしていきたいと考えています。

そこで疑問になったのが、バックエンドではユーザーの状態管理をどのようにするのでしょうか?
フロントエンドでは状態管理をブラウザにお任せしてCookieやセッションストレージに保管することもできますが、
上記LINE BOT制作環境で、ユーザーの状態管理と、ユーザーの状態に合わせた関数の実行はどのようにおこうなのでしょうか。

私の想定ではデータベースを用意して、そこで状態管理をするのかな、、と思っています。
時間を指定した関数の実行はcron?cloudfront?

キーとなる単語や進め方、指針が無く困っております。
関連するワードの羅列でも構いません。皆様のご回答をきっかけに深掘りしていきたいと考えています。
よろしくお願いいたします。

const https = require("https") const express = require("express") const app = express() const PORT = process.env.PORT || 3000 const TOKEN = process.env.LINE_ACCESS_TOKEN const globalValue = {} app.use(express.json()) app.use(express.urlencoded({ extended: true })) app.get("/", (req, res) => { res.sendStatus(200) }) app.post("/webhook", function (req, res) { res.send("HTTP POST request sent to the webhook URL") // ユーザーがボットにメッセージを送った場合、返信メッセージを送る if (req.body.events[0].type === 'message') { globalValue[req.body.events[0].source.userId] = !globalValue[req.body.events[0].source.userId] yourStatus = globalValue[req.body.events[0].source.userId] ? 'true' : 'false' const dataString = JSON.stringify({ replyToken: req.body.events[0].replyToken, messages: [ { "type": "text", "text": "your status is " + yourStatus }, { "type": "text", "text": 'test' } ] }) //リクエストヘッダー const headers = { "Content-Type": "application/json", "Authorization": "Bearer " + TOKEN } // リクエストに渡すオプション const webhookOptions = { "hostname": "api.line.me", "path": "/v2/bot/message/reply", "method": "POST", "headers": headers, "body": dataString } // リクエストの定義 const request = https.request(webhookOptions, (res) => { res.on("data", (d) => { process.stdout.write(d) }) }) // エラーをハンドル request.on("error", (err) => { console.error(err) }) //データを送信 request.write(dataString) request.end() } }) app.listen(PORT, () => { console.log(`Example app listening at http://localhost:${PORT}`) })

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

AWS Lamda , AWS API Gateway , Node.js

こういう奴ですよね
AWS Lambdaって「俺やることやったから落ちるわ」で勝手に死ぬ奴じゃなかったですっけ?
Botと相性悪そうですけど。
なるほど……Webhookで引っ掛けてるだけか。

これだと確かにStateの保存は出来ませんね。
外部に値を保存する仕組みが必要となります。

自分のサービス内で完結するならば一般的に使われるのが永続保存のRDSで、
大企業レベルだと大量のデータを捌く為にDynamoDB等のサービスを比較検討する感じになります。
小規模で高速にデータを取り出したいケースだとRedis等の高速なものを使うのが適しています。

どちらにしてもやってることのショボさの割に
金を取られるのでオススメとは言えません。

まぁ、その程度ならVPSなんかで安くてしょぼいLinuxマシン立ち上げて
そこでちゃんとしたWebサーバとして起動する事を推奨します。
Amazon Lightsailとか

時間を指定した関数の実行はcron?cloudfront?

関数というのはAWS Lambdaにアップロードして使えるようになったものを指しますか?
であれば「AWS スケジュール実行」等で検索したら下記のサービスが出てきました。
スケジュールに従って実行する Amazon EventBridge ルールの作成


Webhookで引っ掛けたLambdaで出来る内容から次の目標を決めるという選択肢もあります。
例えば非IT系な妻との情報共有、「LINE」を駆使したら超捗ったのでオススメさせてください | 男子ハック

こういうのは要するに外部のAPIを叩いているだけなので、
状態は向こう側が保持してくれています。

これをDB代わりに使わせて頂くといった作戦となります。
私はLambdaを使ってはいませんが、
個人的な開発ではGoogle ToDoやTrelloなんかのタスク管理ツールと併用して利用しています。


これはVPS等のLinuxマシンでサービスを立ち上げた場合のやり方になります。

ユーザーが「true」と発言したら、そのユーザーのstatusフラグをtrueにして、

statusフラグがtrueの間、30分おきにBOTからメッセージが送られてくる
ユーザーが「false」と発言したら、そのユーザーのstatusフラグをfalseにする。
といったLINE BOTにしていきたいと考えています。

JavaScript(Node.js)の仕様として
関数で区切られる度に「スコープ」を定義する。
スコープは入れ子になっており、現在スコープに該当の変数が無ければ上に取りに行く。
こういう仕様になっています。

公式チュートリアル
に沿った形でコードを書くならばこんな感じ

js

1const express = require("express") 2const app = express() 3 4// グローバル変数スコープにぶら下げとく 5const statusById = {}; 6 7app.get("/:id", (req, res) => { 8 const id = req.params.id; 9 res.json(statusById[id]); 10}); 11app.put("/:id", (req, res) => { 12 const id = req.params.id; 13 // express.jsはデフォルトでbodyを解析する仕様にはなってないからミドルウェアを噛ます必要ある 14 const status = req.body.status; 15 16 statusById[id] = status == "true"; 17 res.sendStatus(200); 18}); 19app.listen(80);

時間を指定した関数の実行はcron?cloudfront?

VPSのルートならば、そこにLinuxのマシンがポンとあるだけなので
Cronで自動実行のジョブを登録するだけになります。

投稿2021/12/21 03:15

編集2021/12/21 04:43
miyabi-sun

総合スコア21158

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Yusuke_m25

2021/12/21 15:36

ご回答ありがとうございます!! 複数の視点からのアドバイスとても助かります。1つ1つ概要だけでも理解できるようにワードベースで検索をしてみます。 >Webhookで引っ掛けたLambdaで出来る内容から次の目標を決めるという選択肢もあります。 この発想もありがとうございます。今回は逆にLamdaやAWSには拘っていなくて、 ▶︎特定のステータスのユーザーに定期的にメッセージを送る が目標なので、それに合わせた技術選定をするべきなのだなと思いました。(Lamdaで作り始めたのはすぐ検索で出てきたのと、AWSカッケエって下心です) 公式チュートリアルも、確認をしておらずそちらから手を付けてみました。その上でmiyabiさんのコードも取り入れてみたのですが、質問がいくつかあります。 miyabiさんのコードはIDでリクエストをしてグローバルの変数を書き換えているようですが、 私が追記したコードのようにLINEのWEBHOOKからのリクエストに連動させてグローバルの変数を更新しても問題ないですか? そして、このようにプログラムの中でステータス管理ができたとしたら、 もしかしてset intervalを使うことによって定期的に処理をループさせて、毎度グローバル変数のステータスを確認してtrueのユーザーにメッセージを送ることは容易なのではないかと光が見えています。そんな簡単な話ではありませんか?何か懸念点があったら教えてください...(これから試すことを先んじて質問してしまってすみません。) すでに頂いているご回答でとても助かっております。ありがとうございました。 もしお手隙の際に追加でアドバイスいただけるようでしたら幸せです。よろしくお願いいたします。
miyabi-sun

2021/12/22 03:19

> 私が追記したコードのようにLINEのWEBHOOKからのリクエストに連動させてグローバルの変数を更新しても問題ないですか? まぁ大丈夫でしょう。 ちゃんとした企業がこれで金を取るシステムを構築するならば、 同時複数アクセス来た時に整合性ちゃんと取れてるの?正しいデータ取れる?みたいな事を気にする必要があります。 なのでシビアな目線で見るとMySQLやPostgreSQL等のRDBMS使えという話になりますが、 今回のケースはLine Botはその性質上自分一人、多くても10人程度でしか使わないので もしそういう整合性的な不備が出たとしても問題にはならないでしょう。 > res.send("HTTP POST request sent to the webhook URL") 関数実行直後にres.send等のクライアントに文字列返す処理はやめときましょう ギリギリまで待った方が良いです > もしかしてset intervalを使うことによって定期的に処理をループさせて、毎度グローバル変数のステータスを確認してtrueのユーザーにメッセージを送ることは容易なのではないかと光が見えています。 一定間隔程度ならsetIntervalで出来ますが 「この時刻になったら発火」みたいな処理を自前で作るのは地獄ですよ。 npmで配布されているnode-cronとか様々な選択肢があります。 https://qiita.com/n0bisuke/items/66abf6ca1c12f495aa04
Yusuke_m25

2021/12/22 03:34

ありがとうございます。 >関数実行直後にres.send等のクライアントに文字列返す処理はやめときましょう ギリギリまで待った方が良いです この部分はチュートリアルのままにしてしまっていたので、何をしてるのか理解していないままでした。 とりあえずは、アドバイスのとおり理解します。もしよろしければその理由についてもご教示頂けますでしょうか? 妥協して毎30分おきでいいかなと思ったのですが、 本来はユーザーがステータスをtrueにした30分後が理想なので 教えて頂いたモジュール?を確認してみたいと思います! 凄く実装に近づけております。ありがとうございます。
miyabi-sun

2021/12/22 04:21

> その理由 一般的な話ですが、res.sendで送信した文字列は取り消せません。 これが転じて仕様変更やバグの改修に弱いコードになり、 コードを修正することが困難になるからです。 後はres.sendを一度でも行うとヘッダー部分効かないんじゃなかったかな? 追記部分のコードだとヘッダー部分は使用しない宙ぶらりんな感じになってますけど 早期return(ガード節ともいう)のテクニックで「もうこれ以降のコードは書かないよ」というケースや データが出揃うまで書き出すのは遅延しましょう。 https://zenn.dev/media_engine/articles/early_return
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.46%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問