作っているアプリからHTTPに接続するときに、ネットワークの速度を制限したいことがあります。例えば、とても遅いネットワークや海外のインフラが整備されていない地域から接続されるときに、正しく動くかを確認したいときなどです。
WebサーバーをNginxで動かしている場合には、Nginxの設定でネットワークの帯域を制限して、速度を抑えることができます。
Nginxの設定ファイル
Nginxのオフィシャルイメージで動いているDockerコンテナの場合は、/etc/nginx/conf.d/default.conf
ファイルを編集します。コンテナからファイルをコピーして、コンテナを更新する方法については次の記事を参照してください。
帯域制限の設定
帯域制限の設定は、limit_rate
を使います。
limit_rate
次のように使います。50KBPS (50K Bytes Per Second)
に制限している例です。
server {
listen 80;
server_name localhost;
limit_rate 50k
以下省略
}
limit_rate_after
最初は素早く転送して、残りは遅くするという帯域制限をかけることが出来ます。
次のように使います。500KB
転送した後は帯域を制限します。limit_rate
は最初から遅いというシミュレーションができます。limit_rate_after
は途中で失速するようなケースのシミュレーションに使えると思います。
server {
listen 80;
server_name localhost;
limit_rate_after 500k;
limit_rate 50k;
以下省略
}
URLSessionでのタイムアウトの設定
帯域制限のシミュレーションテストを行っていて、クライアントのmacOSアプリから通信するときにタイムアウトの設定をミスしていたことに気がつけました。
2つのタイムアウト
タイムアウトの設定コードが次のようになっていました。
let config = URLSessionConfiguration.ephemeral
config.timeoutIntervalForRequest = 120
config.timeoutIntervalForResource = 120
Nginxで帯域を思いっきり遅くしたので、ダウンロードには3分ほどかかる状態になっています。URLSession
には2種類のタイムアウトがあり、プロパティで設定します。
timeoutIntervalForRequest
(レスポンスが返ってくるまでのタイムアウト)timeoutIntervalForResource
(ダウンロード完了までのタイムアウト)
上のコードの様にプロパティを設定してしまうと、ダウンロードに3分かかるようなときに、2分でダウンロードが中断されてしまいます。正しくは、timeoutIntervalForResource
は設定しないでデフォルト値を使うか、十分に長い値にするかです。十分に長い値がいくつかは、アプリによって異なるでしょう。私の場合は一行消してtimeoutIntervalForResource
はデフォルト値に変更しました。
それと同時に、ダウンロードをタイムアウトで中止してしまったときにも正しく動くことが確認できて良かったです。
ネットワーク側が途切れたときにも確認する
タイムアウトの設定ミスは、アプリ側からダウンロードを中止するユースケースです。逆に、ネットワークが途中で途切れてしまって、ダウンロードできないということも確認するべきでしょう。
途中で切断したときのエラー処理
これにも帯域制限が有効です。帯域制限を行って、ダウンロードに十分時間がかかる状態を作ります。ある程度ダウンロードが進んだところで、次のコマンドを実行し、サーバーをダウンさせてしまいましょう。
% docker-compose down
アプリが正しくエラー処理を実行して、ダウンロード処理を抜けられることを確認します。私の場合はlimit_rate_after
も組み合わせて、半分程度まで一気に進めて、遅くなったところでコマンドを実行しました。
正しくエラー処理が動いて、中止できたことを確認できたら、そのままNginxは停止させたまま、アプリから再接続します。サーバーを動いていないときに正しくエラー処理ができることも確認できます。
ファイルが存在しないときのエラー処理
ここまで確認したら、ついでにファイルが存在しないケースも試します。Dockerで走っているNginxが出力するファイルは、ローカルに置いてあるcontent_home
フォルダ内のファイルです。この中のファイルのファイル名を変更して、意図的にHTTP 403 File Not Found
を発生させます。
アプリで正しくファイルが存在しないときのエラー処理が確認できればOKです。
まとめ
DockerとNginxを組み合わせると、ネットワーク絡みの色々なシミュレーションが手軽にできます。帯域制限は実際に遅い環境などを用意するのは一苦労なので、ローカルマシン内で作れてしまうのはとても便利です。
ネットワークのエラーに強いアプリを作りましょう。