2012-06-21 87 views
12

我在IIS 7.5上運行一個Web應用程序,它需要偶爾回收(否則內存使用將無法處理,我正在調查!)。IIS應用程序池回收+石英調度

當它回收時,直到另一個請求進入,石英不會運行,它實際上不會運行。

有什麼辦法讓IIS在回收應用程序池後立即自動啓動1個工作進程,以確保石英始終在線?

+0

您不應該在Windows Service中託管石英嗎? –

+0

@JakubKonecki,這將是我的計劃b,它只是比在應用程序中託管它更多的努力,因爲調度程序只與應用程序交互。 –

+2

應該已經計劃A ;-) http://haacked.com/archive/2011/10/16/the-dangers-of-implementing-recurring-background-tasks-in-asp-net.aspx –

回答

13

是的!

http://weblogs.asp.net/scottgu/archive/2009/09/15/auto-start-asp-net-applications-vs-2010-and-net-4-0-series.aspx細節也相當不錯,基本上你需要:

  1. 編輯C:\ WINDOWS \ SYSTEM32 \ INETSRV \設置\的applicationHost.config包括:

    <applicationPools> 
        <add name="MyAppWorkerProcess" managedRuntimeVersion="v4.0" startMode="AlwaysRunning" /> 
    </applicationPools> 
    
  2. 聲明一下應作爲您的網站的「熱身」運行

    <sites> 
        <site name="MySite" id="1"> 
         <application path="/" serviceAutoStartEnabled="true" serviceAutoStartProvider="PreWarmMyCache" /> 
        </site> 
    </sites> 
    <serviceAutoStartProviders> 
        <add name="PreWarmMyCache" type="PreWarmCache, MyAssembly" /> 
    </serviceAutoStartProviders> 
    
  3. 配置與任何「熱身」的邏輯程序,你想:

    public class PreWarmCache : System.Web.Hosting.IProcessHostPreloadClient { 
        public void Preload(string[] parameters) { 
         // Perform initialization and cache loading logic here... 
        } 
    } 
    

注意:如果你需要的是w3wp.exe進程是存在我相信,只有第1步是必要的。如果您還需要其他項目(如某些東西要加載到內存中),則也會使用步驟2和3。

+0

對不起,碰到一個老話題,但這個熱身課應該在mvc4項目中的位置? –

+0

@StephenS。謝謝,但它沒有爲我工作,因爲[回收或重新啓動後無法在IIS上保持活動Web應用程序](http://stackoverflow.com/questions/33593602/cannot-keep-alive-web-application-on-iis -after回收有或重啓)。任何幫助嗎? –

+0

對於像我這樣嘗試使用記事本++或其他編輯器來編輯applicationHost.config的人來說,這個答案幫助了(基本上使用記事本):[link](http://stackoverflow.com/a/13335092/2506135) –

0

我在這個問題上採取了一些措施。雖然Stephen's answer將使應用程序繼續運行,但在Spring.Net環境中,框架不會啓動,Quartz將無法運行。我將IProcessHostPreloadClient的一個實現放在一起,這個實例將啓動一個真正的請求到應用程序,以使所有的機器運行。這還張貼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()); 
    } 
} 
-3

或者你可以簡單地修改「的Application_Start」方法在Global.asax中,以確保Quortz運行。

+2

Application_Start僅在回收或啓動後的第一個請求期間被調用,這不是期望的行爲。 –

1

從IIS 8.0開始,有一個選項可以模擬對根頁面的請求,從而完成一個完整的應用程序初始化:應用程序池高級設置 - > Preload enabled = true。

當然,startMode應該是AlwaysRunning。

有關如何啓用此功能的更多詳細信息,請參閱here