[英]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.