ASP.NET & IIS におけるタイムアウトの設定

先日 Session タイムアウトとフォーム認証のタイムアウトを混同している事案を拝見しまして、まぁ ASP.NET あるあるみたいなもんですが、タイムアウト周りは私もよく忘れて痛い目見てますし、ASP.NETIIS にどんなタイムアウト設定があって、どう設定するのかをまとめてみようと思いました。

ちなみに、調べている過程で全く同じことを考えているサイトを見つけたので大いに参考にさせてもらっています。

ASP.NET Timouts (Sessions and App Pools and Auths, Oh My)

前提

.NET 4.5、IIS 8.5 です。.NET Framework が 1.0 や 1.1 と比べると既定値などが変わっている設定もありますが、ここでは省きます。それと、構成ファイルの設定例はできるだけ web.config にしてますが、設定できないものはコメントなどで設定箇所を書いてます。

ASP.NET

Session のタイムアウト

Session のタイムアウト設定です。 セッションタイムアウトはリクエストが受け付けられるたびに有効期限が延びるスライド方式なので、 アイドル状態の Session がタイムアウトするまでの時間を設定することになります。 規定値は 20 分で、最大値は最大値 525,600 分(1 年) です。

設定

IIS マネージャからだと、設定変更したいアプリを選択して、[セッション状態] > [Cookie の設定] > [タイムアウト] から変更できます。

f:id:kendik:20150131012422j:plain

<!-- web.config -->
<system.web>
    <sessionState timeout="20" />
</system.web>

参考

sessionState 要素

フォーム認証タイムアウト

フォーム認証を有効化すると、認証チケットと呼ばれる資格情報を管理するようになります。そして、このチケットに分単位でタイムアウトを設定することができます。

有効期限はリクエストのたびに期限が延びるスライド方式と、発行してからの絶対的な時間でのタイムアウト方式の二種類が選べ、規定値は 30 分です。

認証チケットは一般にクッキーとしてクライアントに発行されますが、クッキーレスでも利用可能なようです。詳しくは参考先のサイトが大変わかりやすいと思います。

設定

IIS マネージャからだと、アプリを選択 > [認証] > フォーム認証を選択 > [操作]ペインの[編集] > [認証 Cookieタイムアウト] から変更できます。

f:id:kendik:20150131012441j:plain

<!-- web.config -->
<system.web>
    <authentication mode="Forms">
        <forms timeout="30" slidingExpiration="false" />
    </authentication>
</system.web>

参考

ASP.NET 認証まわりメモ - はむ日記

authentication の forms 要素 (ASP.NET 設定スキーマ)

Execution Timeout

受け付けたリクエストの処理時間のタイムアウト設定です。 実行したまま何らかの理由でレスポンスを返さない時間が、秒単位で設定されたタイムアウト値に達すると強制的に処理スレッドを終了してくれます。 規定値は 110 秒です。

ただこれ、注意点がいっぱいありまして、、、

まず、compilation 要素の debug 属性が false の時のみしか有効になりません。なので例えば本番環境で発生したから手元でデバッグ実行して再現させて詳細確認~とかはできないですね。それと、強制終了時には HttpException がスローされます(ThreadAbortException って情報もありますが再現できず)。

また、設定値に対してそこまで厳密に動いてくれません。
概ね設定値~設定値+15秒らしいですが、短時間だともうちょっと違ったズレかたするみたいです。自分で試した感じだと、確かに設定値より遅れますが遅れ幅は一定な感じでした。そして、アプリを起動し直すと遅れ幅が変わります。いずれにせよ厳密な精度を求めて使うものではないですね。

そしてさらにさらに、まだあるんですよ、と。IHttpAsyncHandler つまり非同期ハンドラだとそもそも executionTimeout 効きません。なので、最近の ASP.NET MVC では基本利用できません。
同期ハンドラを自分で実装すればいけるんじゃないかと思いますが試してないです。誰かお願いします。
あとは、ちょろっと Server.ScriptTimeout をコード上で設定したらいけるんじゃないかと思ったんですが、これはダメでした。うーん。

という訳で非同期ハンドラではダメですよという話でしたが、非同期ページなら pages 要素の asyncTimeout で同じことができるようです。

ここらへん書くのに参考にしたページを下の方に記載しています。詳しい話はそちらをどうぞ。

設定

で、そんな executionTimeout を IIS マネージャから設定するには、、、どこでするんでしょう?ちょっと見当たりませんでした。とりあえず、困ったときの [構成エディター] から変更することはできますが。。。

<!-- web.config -->
<!-- debug="false" の時のみ有効 -->
<compilation debug="false" />
<system.web>
    <httpRuntime executionTimeout="110" />
</system.web>

参考

httpRuntime 要素 (ASP.NET 設定スキーマ)
pages 要素 (ASP.NET 設定スキーマ)
How the Execution Timeout is managed in ASP.NET
ASP.Net httpruntime executionTimeout not working (and yes debug=false)
web.config executionTimeout not working in ASP.NET MVC

Security Token Handlers

これ全く知らなかったんですが、調べても結局ちゃんと理解しきれませんでした。
WIF に関連する機能で、かつ Security Token とか出てきているのでフェデレーションとかで利用するものなのかもしれません。これによってフォーム認証のタイムアウトを置換できるらしいです。

設定

<!-- web.config -->
<system.identityModel>
    <identityConfiguration>
        <securityTokenHandlers>
            <remove type="System.IdentityModel.Tokens.SessionSecurityTokenHandler,System.IdentityModel,
              Version=4.0.0.0, Culture=neutral,PublicKeyToken=B77A5C561934E089" />
            <add type="System.IdentityModel.Services.Tokens.MachineKeySessionSecurityTokenHandler,System.IdentityModel.Services,
              Version=4.0.0.0, Culture=neutral,PublicKeyToken=B77A5C561934E089">
                <sessionTokenRequirement lifetime="00:20:00"></sessionTokenRequirement>
            </add>
        </securityTokenHandlers>
    </identityConfiguration>
</system.identityModel>

参考

<sessionTokenRequirement>
.NET Framework 4.5 の WIF と "Identity and Access Tool"
Web ファーム!なるほど。

IIS

アプリケーションプール アイドルタイムアウト

アプリケーションプールがアイドル状態で一定時間経過した場合にプロセスを終了させることができるのですが、そのタイムアウト時間を分で設定します。規定値は 20 分です。

設定

IIS マネージャからだと、アプリケーションプールを選んで [詳細設定] > [アイドル状態のタイムアウト] です。

f:id:kendik:20150131012457j:plain

ちなみに、タイムアウト設定の上に [アイドルタイムアウトの操作] という項目がありますが、これは IIS 8.5 の新機能らしく TerminateSuspend が選択できます。 前者は以前から存在する設定で、タイムアウトするとワーカプロセスが停止します。 新設定である後者はプロセス停止はしないものの、ページアウトしてメモリを開けてくれるらしいです。

Windows Server 2012 R2とIIS 8.5の新機能

ワーカープロセスを停止する代わりに、ディスク上からページアウトする。これによりメモリの消費を減らしつつ、ページアウト状態からの復帰にかかる時間を減らしている。

この設定は以下の画面に示す場所で変更できる。具体的には、IISマネージャーの[アプリケーション プール]を開き、設定したいアプリケーションプールの[詳細設定]を開く。プロセスモデルの[アイドル タイムアウトの操作]を「Terminated」から「Suspend」に変更すると適用される。

<!-- applicationHost.config -->
<system.applicationHost>
    <applicationPools>
        <add name="DefaultAppPool" >
            <processModel idleTimeout="00:20:00" />
        </add>
    </applicationPools>
</system.applicationHost>

もしくは

<!-- Machine.config -->
<system.web>
    <processModel timeout="00:20:00" />
</system.web>

参考

processModel 要素 (ASP.NET 設定スキーマ)
アプリケーション プールのアイドル タイムアウト設定を構成する (IIS 7)

アプリケーションプールのリサイクル

アプリケーションプールは定期的にリサイクルといって、まぁ要は再起動的なことを実施することができるのですが、その周期を設定します。設定項目は豊富で

  • 指定した時間経過後
  • 一定の要求数
  • 仮想メモリの最大使用量に到達
  • 最大使用メモリに到達
  • 特定の時刻

が選べます。複数同時設定も可能です。

設定

IIS マネージャからだと、アプリケーションプールを選んで [操作]ペインの > [リサイクルの設定] です。

f:id:kendik:20150131012509j:plain

↓ の config 設定例は、↑ に並んでいる順で、基本的には既定値を設定しています。0 に設定されているものは 無効 です。
「特定の時刻」だけちょっと特別で、既定値は 無効 なんですが、値を設定した時の状態をうまく config 上に表現できなかったのでコメントアウトで例を記載しています。

<!-- applicationHost.config -->
<system.applicationHost>
    <applicationPools>
        <add name="DefaultAppPool" >
             <recycling>
                <periodicRestart
                    requests="0"
                    time="1.05:00:00"
                    memory="0"
                    privateMemory="0" />
                <schedule>
                    <clear />
                    <!-- <add value="00:00:00" /> -->
                    <!-- <add value="12:00:00" /> -->
                </schedule>
            </recycling>
        </add>
    </applicationPools>
</system.applicationHost>

参考

アプリケーション プールのリサイクル設定 アプリケーション プールのリサイクル設定を構成する (IIS 7)

おまけ

ASP.NET Identity クッキー認証タイムアウト

Visual Studio 2013 で 2015/01/30 現在最新の Web アプリケーションテンプレートを使うと、フォーム認証ではなく ASP.NET Identity のクッキー認証が既定になっています。そのクッキー認証のタイムアウト設定です。

設定

// Startup.Auth.cs
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
    AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
    LoginPath = new PathString("/Account/Login"),
    Provider = new CookieAuthenticationProvider
    {
        OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
            validateInterval: TimeSpan.FromMinutes(30),
            regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
    },
    // 以下でタイムアウトを設定
    ExpireTimeSpan = new TimeSpan(0, 20, 0),
    SlidingExpiration = true
});

参考

CookieAuthenticationOptions クラス