開発経験ゼロからの挑戦！AzureFunctionsを使った処理効率化方法と成功するまでの道のり

## はじめに
こんにちは！AgVenture Labの荒井です。
 
Azure Functions、皆さんはご存知ですか？Azure FunctionsはMicrosoftのクラウドサービスで、サーバレス環境でコードを実行できる便利な仕組みです。
実は、私はシステムエンジニアの経験はあるものの、アプリ開発についてはほぼ初心者。
それでもAzure Functionsを使って既存のプロダクトの処理効率化に挑戦してみました。
 
この記事では、そんな初心者がAzure Functionsを使いこなそうと奮闘した体験談をお届け
します。
これを読んでいただければ、初めての方でも自信を持って一歩を踏み出せるはずです！

:::note info
本記事のポイント
・Functionsを用いたサーバ（Java）の処理効率化（非同期化）
・JavaCVでのffmpeg機能実行
・Azure Queue Storageの活用
:::

## 目次
1. [Azure Functionsの利用方法](#azure-functionsの利用方法) 
2. [なぜAzureFunctionsを選んだのか？](#なぜazure-functionsを選んだのか) 
3. [最初の壁：HTTPトリガーのタイムアウト](#最初の壁--httpトリガーのタイムアウト) 
4. [LinuxとWindowsの違いに苦しむ](#linuxとwindowsの違いに苦しむ) 
5. [非同期処理の導入：Functionsを使いこなす](#非同期処理の導入--functionsを使いこなす) 
6. [振り返りと反省](#振り返りと反省) 
7. [最後に：初心者でもできるAzure Functions](#最後に--初心者でもできるazure-functions)

## Azure Functionsの利用方法
はじめに、Azure Functionsを利用してみたい！という方向けに、利用方法をお伝えします。

大まかな流れは
①Azure Portalで関数アプリを作成
②VSCodeから関数アプリに資産をデプロイ
です。

＜①Azure Portalで関数アプリを作成＞
・Azure Portal(https://azure.microsoft.com/ja-jp/get-started/azure-portal/) にサインインし、
「リソースの作成」を押下
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3884142/d4dd0f9d-cc41-6c8c-b3c4-7b222712883c.png)

・「関数アプリ」を押下
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3884142/3afcfb50-7288-203d-72ff-260be1f5861c.png)

・関数アプリ作成の画面に進むので、画面に従って項目を入れる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3884142/a6b2fb28-addc-74fe-5027-f7f80c13a6ff.png)

・作成が完了した後、「関数アプリ」を押すと作成した関数アプリの一覧が表示される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3884142/7844290c-7142-0973-e8eb-1b0312c2c97e.png)

・対象の関数アプリを押下すると、以下の画面が表示される
これで関数アプリの準備はOKです！！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3884142/de3a7892-f227-8191-fadb-5b26fdb4c69c.png)

＜②VSCodeから関数アプリに資産をデプロイ＞
・VSCodeに拡張機能「Azure Functions」を導入する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3884142/bd12e85b-0ba8-be4b-23fa-d47dc31c6a1a.png)

・左下のAzureアイコンを押下し、「Sign in to Azure」を押下
サインインしても良いかの確認のポップアップが出てくるので、「Allow」を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3884142/fb2d6f95-aee2-24ec-76a3-bc10792ef370.png)

・サインインが成功すると一覧が表示される
下の欄のFunctionsアイコン（雷みたいなマーク）を押下し、「Create New Project」を押下
必要項目を入力していくと、任意の場所にレポジトリが作成される
下図のように「Local Project」が作成されたらOK！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3884142/c13c510c-a431-3442-dc15-7f30e23be390.png)

・左上の「ファイル」から「フォルダを開く」を押下し、先ほど作成したレポジトリを選択して開く
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3884142/3a4b3095-5452-acc1-b096-d5d4f073ff20.png)

・開くと、以下のようなFunctions.java等のテンプレートが作成されている
```diff_java
/**
 * Azure Functions with HTTP Trigger.
 */
public class Function {
    /**
     * This function listens at endpoint "/api/HttpExample". Two ways to invoke it using "curl" command in bash:
     * 1. curl -d "HTTP Body" {your host}/api/HttpExample
     * 2. curl "{your host}/api/HttpExample?name=HTTP%20Query"
     */
    @FunctionName("HttpExample")
    public HttpResponseMessage run(
            @HttpTrigger(
                name = "req",
                methods = {HttpMethod.GET, HttpMethod.POST},
                authLevel = AuthorizationLevel.ANONYMOUS)
                HttpRequestMessage<Optional<String>> request,
            final ExecutionContext context) {
        context.getLogger().info("Java HTTP trigger processed a request.");

        // Parse query parameter
        final String query = request.getQueryParameters().get("name");
        final String name = request.getBody().orElse(query);

        if (name == null) {
            return request.createResponseBuilder(HttpStatus.BAD_REQUEST).body("Please pass a name on the query string or in the request body").build();
        } else {
            return request.createResponseBuilder(HttpStatus.OK).body("Hello, " + name).build();
        }
    }
}
```

・VSCode左タブのAzureアイコンを押下し、デプロイしたい関数アプリを右クリック→「Deploy to Function App」でデプロイができます！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3884142/5d390657-10b9-ce8c-d813-4f03d7f88cfd.png)


＜挙動確認＞
デプロイした資産がちゃんと動くかの確認方法です。

・VSCodeでデプロイした資産を右クリック→「Copy Function Url」を押下し、URLをコピー
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3884142/8603570c-2ca5-66c7-696c-06e4a33ad10e.png)

・HTTPクライアントツール（ここではPostman）を使って、先ほどコピーしたURLに向けてGETもしくはPOSTリクエストを送信
ボディに任意のテキストを入れることも忘れずに！

すると、ボディで渡した文字列がリクエストとして返ってくるのを確認できます。
ここまでできたら、あとは好きなようにFunctions.javaの中身をいじってあげるだけです！！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3884142/4d0fc19e-03f2-659d-753b-134967436524.png)


利用方法については以上！
ここから本編開始です〜

## なぜAzure Functionsを選んだのか？
Azure Functionsを選んだ理由はシンプルです。サーバーの処理を効率化し、クライアント側の待機時間を短縮したいと思ったからです。しかし、この時点では「本当に使えるの？」とかなり不安でした。初心者ゆえの心配ですね…。

既存プロダクトの仕様と変更後の仕様は以下の通りです。

＜既存プロダクトの仕様＞
・機能の流れは「動画のアップロード」、「動画の圧縮（Java）」、「Blobストレージへの登録」
・フロントは動画のアップロードを開始したら、サーバの処理が完了するまで待機し、完了次第、他の操作が可能になる
・動画の容量が大きいほど圧縮に時間がかかり、<font color="red">**フロントの待機時間も長くなる**</font>←課題
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3884142/a6a0a899-f975-f903-3b00-babac8a119f3.png)

＜変更後の仕様＞
・時間のかかる圧縮処理をFunctionsで行い、サーバはFunctions呼び出しのみを行うように変更
・Functions呼び出しのタイミングでフロントにレスポンスを返し<font color="red">**フロントの待機時間を短縮**</font>
・Functionsの処理は<font color="red">**非同期**</font>で行う
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3884142/bf3db6a7-8893-5b82-cf3d-dbf7d3ecf598.png)


## 最初の壁 ： HTTPトリガーのタイムアウト
初めて挑戦したトリガーはHTTPトリガー。

>トリガーの種類は以下の公式ドキュメント参照
https://learn.microsoft.com/ja-jp/azure/azure-functions/functions-triggers-bindings?tabs=isolated-process%2Cpython-v2&pivots=programming-language-java

上記の「Azure Functionsの利用方法」でも動かせたし、シンプルかと思いきや、いざ使ってみると大きな問題に直面。
<font color="red">**動画の圧縮に時間がかかりすぎてタイムアウトしてしまう**</font>のです。
230秒の制限があると知ったときは絶望的な気持ちになりました。

ここで公式ドキュメントに救われました。
<font color="red">**タイムアウト期間を最大10分に設定可能なBlobトリガーへと切り替える**</font>ことで解決！初心者でも、このように工夫次第で壁を乗り越えられるんです！
https://learn.microsoft.com/ja-jp/azure/azure-functions/functions-scale

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3884142/d5a21337-b0b2-5a25-1d57-11f34fdae8ea.png)

## LinuxとWindowsの違いに苦しむ
次に直面したのが、開発環境の違い。Azure FunctionsはWindowsとLinuxで動作が異なり、Kuduというツールを使ってFunctions内のファイル配置を確認しようと思ったら…なんと<font color="red">**Linux環境では使えない</font>**！
 
ここでまた、初心者の私にとってはハードルが上がりました。結局、Windows環境へ切り替えて作業を進めることに。うまくいかなくても、落ち着いて対処すれば解決策が見つかるものですね。

ちなみに、以下の手順でKuduを開けます。

・Azure Portalにログイン
・Functionsアプリを選択
・左側のメニューから「開発ツール」→「高度なツール」を開き、「移動」をクリックする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3884142/ca5e7e07-398d-0f7f-4dd5-294531883b58.png)

## 非同期処理の導入 ： Functionsを使いこなす
圧縮処理自体はうまくいきましたが、時間がかかる問題は依然として残っていました。そこで、<font color="red">**非同期処理**</font>を導入。Functionsを使って、圧縮がバックグラウンドで行われるようにし、フロントエンド側の待機時間を大幅に削減することに成功しました！

また、圧縮中かどうかをユーザが把握できるようにするため、<font color="red">**Azure Queue Storage**</font>を活用して”圧縮中”ステータスを追加しました。

:::note info
キューストレージ（Azure Queue Storage）とは、Microsoft Azureが提供するメッセージングサービスで、クラウド上でメッセージを一時保存して情報を非同期にやり取りする機能
:::

＜”圧縮中”表示込みの仕様＞
・サーバのFunctions呼び出し時にキューストレージへキューを追加
・Functionsの圧縮処理完了時に、対象のキューをキューストレージから削除
・フロントが逐次キューストレージを確認し、<font color="red">**キューがあれば”圧縮中”と表示、なければ
”圧縮中”を解除する**</font>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3884142/4b564832-bcf7-6f8f-9443-276de4ad181d.png)


## 振り返りと反省
なんとか実装できたものの、アジャイル開発初心者の私は時間管理に苦労しました。
共有のタイミングが遅れてしまい、次のスプリントに持ち越すことが何度かありました。
また、<font color="red">**事前の調査不足**</font>で、期待していたほどのパフォーマンス向上は実現できなかったことも反省点です。
 
しかし、<font color="red">**Azure Queue Storage**</font>を使って処理状況をユーザーに見せる工夫をしたり、<font color="red">**非同期処理**</font>を導入することで、全体的なユーザー体験を向上させることができました。

## 最後に ： 初心者でもできるAzure Functions
この記事を通じてお伝えしたいのは、初心者でもAzure Functionsを使えば、プロジェクトの処理効率化を実現できるということです。試行錯誤を繰り返しながら、技術を身につけていく過程は楽しいものです。
 
次回は、動画の圧縮処理をさらに高速化するための方法についてお話ししたいと思います。お楽しみに！