IIS 7.5でWebアプリを実行していますが、時々リサイクルする必要があります(そうしないと、メモリ使用量が手に負えなくなり、調査中です!)。
リサイクルする場合、クォーツが実行されない別の要求が来るまで、事実上実行されません。
クォーツが常にオンラインであることを保証するために、アプリプールをリサイクルした直後にIISに1つのワークプロセスを自動的に起動させる方法はありますか?
IIS 7.5でWebアプリを実行していますが、時々リサイクルする必要があります(そうしないと、メモリ使用量が手に負えなくなり、調査中です!)。
リサイクルする場合、クォーツが実行されない別の要求が来るまで、事実上実行されません。
クォーツが常にオンラインであることを保証するために、アプリプールをリサイクルした直後にIISに1つのワークプロセスを自動的に起動させる方法はありますか?
はい!
http://weblogs.asp.net/scottgu/archive/2009/09/15/auto-start-asp-net-applications-vs-2010-and-net-4-0-series.aspxは、それを非常にうまく詳しく説明しています。基本的に次のことを行う必要があります。
C:\ Windows \ System32 \ inetsrv \ config\applicationHost.configを編集して以下を含めます。
<applicationPools>
<add name="MyAppWorkerProcess" managedRuntimeVersion="v4.0" startMode="AlwaysRunning" />
</applicationPools>
サイトの「ウォームアップ」として実行する必要があるものを宣言します
<sites>
<site name="MySite" id="1">
<application path="/" serviceAutoStartEnabled="true" serviceAutoStartProvider="PreWarmMyCache" />
</site>
</sites>
<serviceAutoStartProviders>
<add name="PreWarmMyCache" type="PreWarmCache, MyAssembly" />
</serviceAutoStartProviders>
必要な「ウォームアップ」ロジックを使用してアプリケーションを構成します。
public class PreWarmCache : System.Web.Hosting.IProcessHostPreloadClient {
public void Preload(string[] parameters) {
// Perform initialization and cache loading logic here...
}
}
注:w3wp.exeプロセスが存在するだけでよい場合は、手順1のみが必要であると思います。他のアイテム(メモリにロードする特定のものなど)も必要な場合は、手順2と3も使用されます。
IIS 8.0以降、ルートページへの要求をシミュレートするオプションがあり、アプリケーションを完全に初期化できます。アプリケーションプールの詳細設定->プリロードが有効=true。
もちろん、startModeはAlwaysRunningである必要があります。
この機能を有効にする方法の詳細については、こちらをご覧ください。
私はこの問題にひびを入れました。Stephenの答えはアプリを実行し続けますが、Spring.Net環境では、フレームワークは開始されず、Quartzは実行されません。すべての機械を実行するために、アプリケーションへの実際の要求を実行するIProcessHostPreloadClientの実装をまとめました。これは私のブログにも投稿されています:
public class Preloader : System.Web.Hosting.IProcessHostPreloadClient
{
public void Preload(string[] parameters)
{
var uris = System.Configuration.ConfigurationManager
.AppSettings["AdditionalStartupUris"];
StartupApplication(AllUris(uris));
}
public void StartupApplication(IEnumerable<Uri> uris)
{
new System.Threading.Thread(o =>
{
System.Threading.Thread.Sleep(500);
foreach (var uri in (IEnumerable<Uri>)o) {
var client = new System.Net.WebClient();
client.DownloadStringAsync(uris.First());
}
}).Start(uris);
}
public IEnumerable<Uri> AllUris(string userConfiguration)
{
if (userConfiguration == null)
return GuessedUris();
return AllUris(userConfiguration.Split(' ')).Union(GuessedUris());
}
private IEnumerable<Uri> GuessedUris()
{
string path = System.Web.HttpRuntime.AppDomainAppVirtualPath;
if (path != null)
yield return new Uri("http://localhost" + path);
}
private IEnumerable<Uri> AllUris(params string[] configurationParts)
{
return configurationParts
.Select(p => ParseConfiguration(p))
.Where(p => p.Item1)
.Select(p => ToUri(p.Item2))
.Where(u => u != null);
}
private Uri ToUri(string value)
{
try {
return new Uri(value);
}
catch (UriFormatException) {
return null;
}
}
private Tuple<bool, string> ParseConfiguration(string part)
{
return new Tuple<bool, string>(IsRelevant(part), ParsePart(part));
}
private string ParsePart(string part)
{
// We expect IPv4 or MachineName followed by |
var portions = part.Split('|');
return portions.Last();
}
private bool IsRelevant(string part)
{
var portions = part.Split('|');
return
portions.Count() == 1 ||
portions[0] == System.Environment.MachineName ||
HostIpAddresses().Any(a => a == portions[0]);
}
private IEnumerable<string> HostIpAddresses()
{
var adaptors = System.Net.NetworkInformation
.NetworkInterface.GetAllNetworkInterfaces();
return adaptors
.Where(a => a.OperationalStatus ==
System.Net.NetworkInformation.OperationalStatus.Up)
.SelectMany(a => a.GetIPProperties().UnicastAddresses)
.Where(a => a.Address.AddressFamily ==
System.Net.Sockets.AddressFamily.InterNetwork)
.Select(a => a.Address.ToString());
}
}
または、Global.asaxの「Application_Start」メソッドを変更して、Quortzが実行されていることを確認することもできます。