问题
I'm running a web app on IIS 7.5 and it needs to recycle occasionally (otherwise memory usage gets out of handing, something i'm looking into!).
When it recycles, it is effectively not running until another request comes in, which quartz is not going to run.
Is there any way to have IIS automatically bring up 1 work process immediately after recycling the app pool to ensure quartz is always online?
回答1:
Yes!
http://weblogs.asp.net/scottgu/archive/2009/09/15/auto-start-asp-net-applications-vs-2010-and-net-4-0-series.aspx details it quite nicely, basically you need to:
Edit C:\Windows\System32\inetsrv\config\applicationHost.config to include:
<applicationPools> <add name="MyAppWorkerProcess" managedRuntimeVersion="v4.0" startMode="AlwaysRunning" /> </applicationPools>
Declare what should be run as the "warm-up" for your site
<sites> <site name="MySite" id="1"> <application path="/" serviceAutoStartEnabled="true" serviceAutoStartProvider="PreWarmMyCache" /> </site> </sites> <serviceAutoStartProviders> <add name="PreWarmMyCache" type="PreWarmCache, MyAssembly" /> </serviceAutoStartProviders>
Configure your application with whatever "warm-up" logic you would like:
public class PreWarmCache : System.Web.Hosting.IProcessHostPreloadClient { public void Preload(string[] parameters) { // Perform initialization and cache loading logic here... } }
Note: If all you need is for the w3wp.exe process to be present I believe only step 1 is necessary. If you also need other items (like certain things to be loaded into memory) then step 2 and 3 would also be used.
回答2:
Starting with IIS 8.0, there is an option to simulate a request to the root page, thus a full application initialization: Application Pool advanced settings -> Preload enabled = true.
Of course, startMode should be AlwaysRunning.
More details about how to enable this feature can be found here.
回答3:
I took a crack at this problem. While Stephen's answer will keep the app running, in a Spring.Net environment, the framework won't kick off and Quartz will not run. I put together an implementation of IProcessHostPreloadClient that will fire off a real request to the application in order to get all the machinery running. This is also posted on my blog:
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());
}
}
回答4:
Or you could simply modify the "Application_Start" Method in Global.asax to ensure that Quortz is running.
来源:https://stackoverflow.com/questions/11140597/iis-app-pool-recycle-quartz-scheduling