事象
LINE Messaging APIで音声や動画データを取得しこれらを保存するするとデータが空もしくは欠損している事象が発生した。
検証環境
CPU: Apple M1
OS: MacOS Monterey 12.6.3
Node.js: v16.18.1
LINE Bot SDK(Node.js) Version: 7.5.2
事象発生サーバ環境
インフラ: Fly.io(Firecracker VM)
Node.js: v16.18.1
LINE Bot SDK(Node.js) Version: 7.5.2
今回事象の背景
LINEでシェアするファイルは一定期間たつとアクセスできなくなる。
僕の所属するLINEグループによっては恒久的にデータを保存し参照できるようにしたいというニーズがあった。
よって音声データや動画データを保存できるように、LINE Botにデータを渡し、LINE BotサーバでGoogle Driveに送信ファイルを保存するようにしていた。
LINE Botサーバに送信されるファイルデータは問題なく保存されてたが、音声データと動画データは空データもしくは欠損した状態で保存されていることに気がついた。
下記手順を実行すると発生する。
- 検証対象のLINE Botに対して任意の音声データ or 動画データを送信する
- サーバでデータをファイルに書き込み保存する
音声データや動画データは数MBであった。
原因特定の流れ
下記を切り分ける
- ファイルデータは保存されていること
- 音声データ、動画データのみうまくいっていないこと
LINE Messaging APIの公式ドキュメントを参照すると、下記を発見した。
https://developers.LINE.biz/ja/reference/messaging-api/#get-content
音声データ、動画データに関してLINEのサーバの提供準備の完了をまたずに取得処理を実行していたからではという仮説がたつ。
実際処理の直前に上記APIを呼ぶとprocessing(コンテンツの取得準備中)という結果が帰ってきた。
原因
当該事象のの原因はLINE Botサーバで音声データもしくは動画データの送信準備が整っていないのに、Botサーバで取得をおこなったため。
解決方法
下記APIを使用して、動画または音声の取得準備の状況を確認するようにした。
GET https://api-data.LINE.me/v2/bot/message/{messageId}/content/transcoding
上記APIは下記のいずれかの値を返却する
-
processing
:コンテンツの取得準備中である。 -
succeeded
:コンテンツを取得する準備が完了した。 -
failed
:コンテンツの取得準備に失敗した。
上記APIを定期実行しsucceeded
の場合のみ保存処理に進むように実装を修正した。
下記のようなコードで完了を待機できる。
待機用の関数
const _sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
// (中略)
// 動画または音声の取得準備の状況を確認する(Node-fetchを使用している)
let res = await fetch(`https://api-data.LINE.me/v2/bot/message/${id}/content/transcoding`, {
method: "GET",
headers: {
Authorization: `Bearer ${LINE_ACCESS_TOKEN}`,
},
});
let resJson = await res.json();
let maxCheck = 10;
// 成功するまで確認を行う。
while (resJson.status !== 'succeeded') {
await _sleep(1000);
maxCheck--;
if (maxCheck === 0) {
// 確認する上限に達したらやめる(暫定で設定)
console.log(`failed to get data id${id}`);
break;
}
// 動画または音声の取得準備の状況を確認する
res = await fetch(`https://api-data.LINE.me/v2/bot/message/${id}/content/transcoding`, {
method: "GET",
headers: {
Authorization: `Bearer ${LINE_ACCESS_TOKEN}`,
},
});
// ここで音声データもしくは動画データを取得するようにする
以上。