【问题标题】:Site stops working after custom keep alive functionality自定义保持活动功能后站点停止工作
【发布时间】:2021-03-21 21:34:57
【问题描述】:

我最近部署了一个在共享托管环境中运行的站点。问题是该站点接收到零星的流量:20 分钟后,我想服务器关闭了实例,因此当站点加载第一个请求时,它通常很慢。所以我决定添加一个每隔几分钟加载一次网页的功能。我用new CodeKeepAlive.KeepAliveManager().SetKeepAlive(); 调用 Global.asax 中的代码,这是完整的代码:

public class KeepAliveManager
{
    Timer KeepAliveTimer;

    public void SetKeepAlive()
    {
        KeepAliveTimer = new Timer(DoKeepAliveRequest, null, new Random().Next(200000, 900000), Timeout.Infinite);
    }

    public void DoKeepAliveRequest(object state)
    {
        string TheUrl = "https://www.the_website_url.com";

        HttpWebRequest TheRequest = (HttpWebRequest)WebRequest.Create(TheUrl);
        HttpWebResponse TheResponse = (HttpWebResponse)TheRequest.GetResponse();

        KeepAliveTimer.Change(new Random().Next(200000, 900000), Timeout.Infinite);
    }
}

由于某种原因,由于我添加了此功能,因此网站偶尔会锁定一次;加载时间 30 秒后,服务器说无法加载页面。我还有一个在Application_Error 上触发的错误日志记录功能,但没有日志。

我的代码有什么问题吗?

【问题讨论】:

  • 结帐Do C# Timers elapse on a separate thread? 看看你用的是什么类型的计时器。由于您每次都在进行 HTTP 调用,因此该站点可能已锁定。确保计时器回调在单独的线程上运行。无论如何,你正在做一个丑陋的黑客攻击,并没有解决你声称的服务器关闭实例的正确问题。
  • 您是否可以在 IIS 中为站点使用单独的应用程序池并将其配置为不关闭?
  • 为什么不简单地禁用或延长应用程序池 20 分钟的关闭时间?或者制作一个充当保活工具的 Windows 服务。
  • 而且,如果您的保活代码存在一个问题,则可能是响应未关闭 (TheResponse.Close()),这可能导致连接不足。毕竟无法与服务器建立新的连接。
  • 查看 IIS 中的空闲超时

标签: c# asp.net shared-hosting


【解决方案1】:

问题出在 asp.net 中,没有可靠的方法来运行后台任务而不会有 IIS 杀死您的线程的风险。一旦请求完成,IIS 就没有理由让您产生的任何线程保持活动状态。

有几种方法可以做到这一点,例如使用亚马逊或谷歌云免费层上的一些简单服务来充当你的心跳。

但假设您只想使用共享主机

您可以使用类似 HangFire 的东西,它专门用于此,但它们有其局限性,请参阅 docs for getting started

GlobalConfiguration.Configuration
    .SetDataCompatibilityLevel(CompatibilityLevel.Version_170)
    .UseSimpleAssemblyNameTypeSerializer()
    .UseRecommendedSerializerSettings()
    .UseSqlServerStorage("Database=Hangfire.Sample; Integrated Security=True;", new SqlServerStorageOptions
    {
        CommandBatchMaxTimeout = TimeSpan.FromMinutes(5),
        SlidingInvisibilityTimeout = TimeSpan.FromMinutes(5),
        QueuePollInterval = TimeSpan.Zero,
        UseRecommendedIsolationLevel = true,
        UsePageLocksOnDequeue = true,
        DisableGlobalLocks = true
    })
    .UseBatches()
    .UsePerformanceCounters();

//Queue the job
BackgroundJob.Enqueue(() => Console.WriteLine("Hello, world!"));

//run it
using (var server = new BackgroundJobServer())
{
    Console.ReadLine();
}

注意: Hang Fire 它自身有其局限性 IIS 将关闭任何长时间运行的线程,例如需要 90 或 180 秒以上的线程(我忘记了限制)所以请确保将您的每个传入请求的心跳任务。如果您想确保不会触发太多,可以在请求中添加标头并验证它是否在请求中。

在新的.Net-Core Background Tasks 上查看此答案,因为它与 IIS 相关,所以适用

【讨论】:

  • 您还可以使用其他一些肮脏的技巧。例如,通过向自己发出请求并使用semiphore 等到另一个线程请求该资源并返回来强制长拉控制器方法。这样,您就可以确定在让 iis 知道请求完成之前已经触发了另一个心跳
【解决方案2】:

在 PhantomJs 中添加一个测试程序,用于随机或定期截取 url 并部署在同一服务器上。 IT 将为您完成这项工作

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-03-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-07
    • 1970-01-01
    相关资源
    最近更新 更多