簡體   English   中英

在IIS中重新啟動網站時,如何檢索已啟動的Ignite實例?

[英]How do I retrieve a started Ignite instance when a website restart occurs in IIS?

我在ASP.NET MVC 5網站中使用Apache Ignite .NET EntityFramework二級緩存。 一切都在我的開發機器上按預期工作,但當我嘗試在生產IIS上使用Web Deploy發布網站時,事情變得復雜。

我總是得到一個class org.apache.ignite.IgniteException: Ignite instance with this name has already been started: GridName當我在IIS上發布或重新啟動網站時, class org.apache.ignite.IgniteException: Ignite instance with this name has already been started: GridName 錯誤非常明顯,Ignite已經在運行。

我發現逃避此錯誤的唯一方法是重新啟動網站的應用程序池。 但是,每次我在生產中發布網站(每周發生幾次)時,我都不想這樣做。

我嘗試在global.asax Dispose()或Application_End()中停止Ignite實例,但事實是AppDomain需要很多秒才能停止。 因此,Ignite有時間在停止之前嘗試自行啟動並導致上述錯誤。

我還嘗試調用Ignition.TryGetIgnite()來檢索正在運行的實例,而不是嘗試啟動它,但它總是返回null。 在Apache Ignite Github存儲庫中查看此函數的源代碼,我看到Ignition對象只是在內存中保留一個靜態節點列表並在此列表上執行操作。 由於此時AppDomain重新啟動,因此列表為空,但Ignite節點仍在JVM中運行。

有沒有辦法檢索Ignite實例或可靠地停止它,所以我不需要每次都重啟應用程序池?

這是一個已知問題:AppDomain已停止,但JVM仍在運行(因為進程未停止),因此Ignite節點的Java部分仍然存在。

解決方法是在Global.asax.cs中的Application_End事件中使用Ignition.StopAll停止所有Ignite節點:

    protected void Application_Start()
    {
        ...

        using (new Mutex(true, "ignite_" + Process.GetCurrentProcess().Id))
        {
            var ignite = Ignition.TryGetIgnite() ?? Ignition.Start();
        }
    }

    protected void Application_End()
    {
        using (new Mutex(true, "ignite_" + Process.GetCurrentProcess().Id))
        {
            Ignition.StopAll(true);
        }
    }

此處需要互斥鎖,因為舊域停止與新域啟動重疊。 進程ID包含在互斥鎖名稱中,以確保進程范圍的獨占鎖定,但不是機器范圍的。


另一個解決方法 ,可能更強大和干凈:

1)停止AppDomain.DomainUnload中的所有節點:

AppDomain.CurrentDomain.DomainUnload += (sender, args) => Ignition.StopAll(true);

2)每次使用不同的IgniteConfiguration.GridName

Ignition.Start(new IgniteConfiguration { GridName = Guid.NewGuid().ToString() });

這樣,現有節點不會阻止您啟動新節點。 最終,舊節點將被停止並從內存中清除。

文檔: https//apacheignite-net.readme.io/docs/deployment#section-aspnet-deployment

不完全是我想要的,但我暫時解決了這個問題。

我所做的是在Application_End ,我按照Pavel的建議調用Ignition.StopAll() ,但由於Application_End有時需要很長時間才能被調用,因此為網站加載的新AppDomain有時間啟動並在Ignite停止之前接收請求另一個AppDomain。

為了解決這個問題,我使用以下代碼啟動Ignite(可以改進):

//Try to get already launched Ignite Instance
IIgnite ignite = Ignition.TryGetIgnite(igniteName);

while (ignite == null)
{
    try
    {
        //Try to start Ignite
        ignite = Ignition.Start(igniteConfig);
    }
    catch (Exception) //If failing to start Ignite, wait a bit for the previous AppDomain to stop the Ignite running instance...
    {
        HttpRequest request = null;
        try
        {
            request = HttpContext.Current.Request;
        }
        catch { }

        //Check if there is a request coming from the same machine, if yes, cancel it.
        if (request == null || !(request.IsLocal || request.UserHostName.EndsWith("myhostname.com"))
            Thread.Sleep(1000);
        else
            throw new HttpException(500, "Server error. Server rebooting.");
    }
}

//Use ignite variable here...

請注意,在上面的代碼中,我進行了額外的檢查(每個人可能不需要),以檢查是否有來自同一台機器的當前請求。 如果你想知道原因,請閱讀下面的內容,否則只需獲取代碼並刪除最后一個if else部分,然后保留Thread.Sleep()

如果請求來自同一台機器,則拋出HttpException以取消請求,否則,它將被保留。 我放這個代碼的原因是,如果我在IIS上發布網站,我不希望消費者看到錯誤,但我不介意他們等待前一個AppDomain停止。 但是,如果我收到來自同一台機器(或網站)的請求,我希望請求中止,因為它可能源自舊AppDomain的代碼,因此會延遲舊AppDomain中的Application_EndIgnition.StopAll()

希望未來的一些Apache Ignite .NET開發可以使實例關閉比這種解決方案更容易,更可靠。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM