![](/img/trans.png)
[英]How do I enable ignite-http-rest module when using the .Net NuGet Apache Ignite package?
[英]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_End
和Ignition.StopAll()
。
希望未來的一些Apache Ignite .NET開發可以使實例關閉比這種解決方案更容易,更可靠。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.