繁体   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