# actix-web を IIS にデプロイ (perl cgi との比較)

試しに actix サーバを IIS にデプロイしてみた話。

もとが perl cgi をリプレイスした方がいいんじゃないかという話だったのでちょっとだけ速度比較もしてみた。
細かい手順については様々な記事が存在しているのであまり深くは触れません。

## 概要

- HttpPlatformHandler でIISにデプロイする
- perl CGI よりもちょっと速い

## HttpPlatformHandler

IIS でのバックエンドプログラムの実行方法は CGI とか FastCGI、
[HttpPlatformHandler](https://www.iis.net/downloads/microsoft/httpplatformhandler) などがある。

.NET のプログラムだと .NET 用のモジュールを使うのが良さそうだが、その他の exe 形式のものを使う場合はこれが良さそう。
fastapi について調べた時はこれが推奨されていた。（[参考](https://learn.microsoft.com/ja-jp/visualstudio/python/configure-web-apps-for-iis-windows?view=vs-2022))

rust についてもこれと同じ感じでデプロイできる。

### デプロイの流れ

とりあえず流れと要点だけ。

- rust ソースをビルド
  - `--release` オプションを適宜使う。
- `web.config` を作成
  - `web.config` は IIS にデプロイする際の設定ファイル
  - 詳細は後述
- IIS サーバにビルドしたファイルと `web.config` を配置
  - どこでも良いが、`C:\inetpub\wwwroot` がよくある置き場所
- IIS にアプリケーションを追加
  - 物理パスは 3 で配置した場所
  - URL 構成とかは適宜設定する
- 実行権限の付与
  - 3 のフォルダについて、`IIS_IUSRS` に実行権限を付与する
  - perl や python で exe が別フォルダにあるときはそちらにも権限をつける

### web.config

```xml
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.webServer>
    <handlers>
      <add name="PythonHandler" path="*" verb="*" modules="httpPlatformHandler" resourceType="Unspecified"/>
    </handlers>
    <httpPlatform processPath="C:\inetpub\wwwroot\<実行ファイルのパス>"
                  arguments=""
                  stdoutLogEnabled="true"
                  stdoutLogFile="<ログファイルのパス>"
                  startupTimeLimit="60"
                  processesPerApplication="1">
      <environmentVariables>
        <environmentVariable name="SERVER_PORT" value="%HTTP_PLATFORM_PORT%" />
        <environmentVariable name="BASE_PATH" value="/actix" />
      </environmentVariables>
    </httpPlatform>
  </system.webServer>
</configuration>
```

`BASE_PATH` はアプリケーションの URL のベースパス。環境変数で渡す形にしてみた。

`SERVER_PORT` の末尾に謎のスペースが入ったので、`trim` してからパースした。

```rust
let port: u16 = std::env::var("SERVER_PORT")
    .unwrap_or("8080".to_string())
    .trim()
    .parse()
    .unwrap();
```

## 速度比較

perl cgi、rust で作った exe を cgi として実行したものと actix の exe を HttpPlatformHandler で実行したものを比較。

python のrequests でGETリクエストした時のレスポンスタイムを比較。

純粋な実行速度の比較というよりは、ネットワークを経由するときの諸々を比べる感じ。

コールドスタートを考慮して、１０回リクエストした後に５０回リクエストした平均をとっている。
が、今回はコールドスタートにならなかった。

### テキストを返すだけ

単位は秒。小数点以下第五位で切り捨て。

|  | perl | rust (cgi) | rust (actix) |
| --- | --- | --- | --- |
| 初回 | 0.0998 | 0.0944 | 0.0657 |
| ５０回平均 | 0.1020 | 0.0915 | 0.0652 |

### DB からデータを取得して返す

一つのテーブルの全データ (250Byte 程度) を返すだけのシンプルなクエリ。

単位は秒。小数点以下第五位で切り捨て。

|  | perl | rust (cgi) | rust (actix) |
| --- | --- | --- | --- |
| 初回 | 0.3852 | 0.1809 | 0.1267 |
| ５０回平均 | 0.3880 | 0.1964 | 0.1395 |

## 詰まったところのメモ

actix で postgres クレートを使ってDB接続する時に、非同期関数を呼び出せない場面があった。

`rust cannot start a runtime from within a runtime` のエラー。

tokio の main がスレッドのロックか何かをしていることが原因の模様。[tokio のイシュー](https://github.com/tokio-rs/tokio/discussions/3857)にもある。
actix の main が `tokio::main` として動いている時に postgres クレートも `tokio::main`
として動こうとするので動けないっぽい。

[こちらの記事](https://qiita.com/aoyagikouhei/items/09c1b047d91b360ab277)を参考に`web::block` を使って解決。

### 感想

actix を HttpPlatformHandler で使うのが速いという結果になった。
cgi の方が exe を直接実行してそうで速いかもと思っていたので、ちょっと意外。

actix にはデバッグ用のプリント文が入っているがそれでも速い。
cgi だと標準出力を拾って整形してるっぽいので、その辺のオーバーヘッドかもしれない。

perl での DB 接続は、モジュールの都合かもしれないが遅い。

データ量が増えてくれば別の問題も出てきて速度に影響してくるかもしれない。

## おわりに

mac から windows 向けのクロスコンパイルも実施できた。
windows + wsl のときにはうまくいかなかいことがあったのでちょっとうれしい。

perl と cgi にもちょっと詳しくなった()。

ついでに FastCGI とか python との比較も試そうと思ったのだが、実行時エラーになったので断念。