あえて今書いてみるREALITYチャットでのGIF投稿機能の仕組み REALITY Advent Calendar 2024
REALITY Advent Calendar 6日目担当のサーバーエンジニアの@sola-msrで
す!(2投稿目!)
アドベントカレンダーなんてなんぼ書いてもいいですからね(?)、今回はこの間、提供が終了したREALITYチャット内にあったGIF投稿機能の仕組み(特にサーバー側)について、ここに書き残しておこうかなと思います。
REALITYチャットのGIF投稿機能とは
REALITY内チャットにあったGIF画像を投稿できる機能「GIF投稿機能」ですが、REALITY内のチャットで使ったことがないよ、という方でも、X(Twitter)やFacebookなどのSNSでも使用できるのでご存じの方は多いとは思います。
どのような機能かを簡単に説明すると、動くおもしろい画像(GIFアニメーション)をまるでスタンプのように送り合うことができる機能でした。
(この記事を執筆している時点で、「GIF投稿機能」は諸事情により提供を終了させていただいております。)
ちなみにこの機能は、外部サービスの GIPHY というサービスのAPIを利用させていただいておりました。
GIF投稿機能の仕組み
基本的には以下のイメージのような仕組みで動いておりました。
クライアントであるREALITYアプリからGIPHYへGIF画像一覧を要求・取得し、その内選択されたGIF画像のID(GifID)をREALITYサーバー側で受け取り、それを再びGIPHYAPI経由でGIPHYへ問い合わせを行っていました。そこで本当にGIPHYに存在するGIF画像かのバリデーションを行って、問題なかったらチャット関連のデータストアにIDを保存し、クライアントへGIF画像を表示させるための情報を返し、GIF画像を表示する、という仕組みです。
この際、内部の処理の途中でどうしても外部サービスであるGIPHYに問い合わせを行うので、GIF画像が表示されるまでのレスポンスが遅くなってしまう問題があったのですが、Go言語のゴルーチンを用いて出来る限り内部処理を並列化し、レスポンスの最適化を行うようにしました。
var wg sync.WaitGroup
var mu sync.Mutex
errList := make([]error, 0, 2)
wg.Add(1)
// クライアントから渡されたgifIDの検証
go func() {
defer wg.Done()
res, err := giphy.ValidateGiphy(gifID)
if err != nil {
mu.Lock()
errList = append(errList, err)
mu.Unlock()
return
} else if res.Validate == false {
mu.Lock()
errList = append(errList, errors.New("GifID is invalid"))
mu.Unlock()
return
}
// その他の処理(以下略)
}()
wg.Add(1)
// チャットにまつわる処理
// (送信先やユーザーの状態、設定などの処理をバリデーションの裏側で行なっておく)
go func() {
defer wg.Done()
res, err := chat.check(userID)
if err != nil {
mu.Lock()
errList = append(errList, err)
mu.Unlock()
return
}
// その他の処理(以下略)
}()
wg.Wait()
if len(errList) > 0 {
// 初めに追加されたエラーを返す
c.Err = errList[0]
return
}
並列化することで結果的に平均1秒以下、時間がかかっていた場合でも約1.5秒ほどに抑えることができ、大幅に速度改善することができました!
おわりに
GIF投稿機能以外にも、このように処理の最適化を行っており、数年前と比べるとサーバー全体のレスポンス速度と安定性が改善されております。
(その取り組みについては以下の記事をご覧ください。)
いつの日か、また似たような機能やこの知見が活かせる機能を開発するとなった際にはこの記事を参考に思い出して実装しようと思います。
他のアドベントカレンダーも沢山ありますので、気になった方はぜひ見てみてください!(自分のもう一つの記事の方もよろしくお願いいたします!)
それでは!