エラー内容
acitx-webの公式サイトのGetting Startedをdockerコンテナで動かしていました。ローカル環境では動いていたのですが、herokuにデプロイするとApplication errorが出て正常に動作しませんでした。
heroku logs --tail
コマンドで確認するとError R10 (boot timeout)
というエラーが出ていました。
$ heroku logs --tail
;; 抜粋
Error R10 (Boot timeout) -> Web process failed to bind to $PORT within 60 seconds of launch
Stopping process with SIGKILL
Process exited with status 137
State changed from starting to crashed
herokuの公式サイトで調べるとherokuでは環境変数$PORT
がデフォルトで設定されていて、dyno(heroku上で動いているアプリコンテナ)はこの環境変数$PORT
で表されるポート番号でリッスンする必要があるみたいです。
webサーバー
Heroku の外部では、Web アプリが Web サーバーコンテナの内側で実行されることがあります。たとえば、PHP アプリが Apache HTTPD 内部でモジュールとして実行されたり、Java アプリが Tomcat 内部で実行されたりします。Heroku では、アプリは完全に自己完結型です。Web サーバーによる実行環境へのランタイムインジェクションを使用して Web 対応サービスをつくり出すのではありません。各 Web プロセスがポートに結合して、そのポートで着信するリクエストをリスンするだけです。結合する相手のポートは、Heroku により PORT 環境変数として割り当てられます。
ローカル環境変数
Dyno Manager により、アプリケーション内でアクセスできる多数のデフォルト環境変数が設定されます。
- dyno が Web dyno である場合は、$PORT 変数が設定されます。 dyno が受信リクエストを受け取るには、このポート番号にバインドする必要があります。
R10-ブートタイム
Webプロセスは、割り当てられたにバインドするのに60秒以上かかりました$PORT。これが発生すると、dynoのプロセスが強制終了され、dynoがクラッシュしたと見なされます。クラッシュしたdynoは、dynoマネージャーの再起動ポリシーに従って再起動されます。
修正
環境変数$PORT
を読み込んできてその値をポート番号としてバインドするようにしました。ローカル環境で環境変数$PORT
がない場合でも動かせるようにデフォルトで8080を設定するようにしています。
use actix_web::{get, post, web, App, HttpResponse, HttpServer, Responder};
+ use std::env;
#[get("/")]
async fn hello() -> impl Responder {
HttpResponse::Ok().body("Hello world!")
}
#[post("/echo")]
async fn echo(req_body: String) -> impl Responder {
HttpResponse::Ok().body(req_body)
}
async fn manual_hello() -> impl Responder {
HttpResponse::Ok().body("Hey there!")
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
+ let port = env::var("PORT")
+ .unwrap_or_else(|_| "8080".to_string())
+ .parse()
+ .expect("PORT must be anumber");
HttpServer::new(|| {
App::new()
.service(hello)
.service(echo)
.route("/hey", web::get().to(manual_hello))
})
- .bind(("0.0.0.0", 8080))?
+ .bind(("0.0.0.0", port))?
.run()
.await
}
正常動作
修正してherokuにデプロイするとちゃんとHello world!が表示されるようになりました。