保持负载均衡器在长时间运行期间不会超时

时间:2012-10-04 22:21:56

标签: asp.net asp.net-mvc load-balancing

我正在使用ASP.NET MVC 4接受最大30 mb的视频上传。将视频上传到网站后,视频将使用HttpWebRequest发布到第三方Web服务。此上传到第三方服务必须完成并返回响应,然后我的网站才能向浏览器返回响应。在Rackspace Cloud Sites上,负载均衡器有30秒超时。如果我的站点没有通过负载均衡器返回响应30秒,则负载均衡器会向浏览器返回超时错误并终止请求。

所以我被告知需要发生的事情是,我的网站需要通过在我的网站将视频发送到第三方系统时将数据发送回浏览器来保持连接活动,以便负载均衡器不会t超时。你将如何完成这项任务?

我正在寻找两件事 - 在上传过程中,我将哪些数据作为数据发送回浏览器?我的实际响应是JSON,所以如果我能在最后保持我的常规JSON响应,那将是理想的。

最后,如何在同时发送保持活动数据的同时将HttpWebRequest上传到第三方?

-

作为参考,这是来自rackspace cloud的负载均衡器连接超时文档:http://www.rackspace.com/knowledge_center/article/connection-timed-out-error-message-1

他们没有为这个问题提供任何具体的解决方案。

2 个答案:

答案 0 :(得分:3)

以下是我解决问题的方法。此解决方案应适用于任何使用负载均衡器且具有不合理超时的.net主机。 Rackspace Cloud Sites在其负载均衡器上有30秒超时。亚马逊和Azure有更长的超时时间,但如果碰巧长时间运行,这仍然可能是一个有用的解决方案。

在asp.net mvc 4中,您可以将控制器更改为从AsyncController继承。这允许您分离异步任务,然后等待它们完成。此解决方案创建一个“保持活动”任务,每10秒通过asp.net响应发回数据,以便负载均衡器检测到活动并且不会超时。此任务一直运行,直到它看到uploadFinished变量设置为true。

另一个任务执行长时间上传,或者在asp.net mvc控制器结束它正在处理的Web请求之前需要完成的任何任务。在长时间运行操作完成后,它将uploadFinished变量设置为true。

最后,我在实际的json响应周围手动构建一个容器json对象,这样我就可以将“keep alive”数据作为有效json的一部分发送回浏览器。一个稍微丑陋的黑客,但它确实有效!

using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using System.Web.Mvc;
using System.Web.Script.Serialization;

namespace MvcApplication4.Controllers
{
    public class ExampleController : AsyncController
    {

        [HttpPost]
        public string Upload(UploadModel model, HttpPostedFileBase videoFile)
        {
            // when using jquery ajax form for upload
            // IE requires text/plain content type
            // otherwise it will try to open the response as a file
            // instead of pass the response back to your javascript
            if (Request.AcceptTypes.Contains("application/json"))
            {
                Response.ContentType = "application/json";
            }
            else
            {
                Response.ContentType = "text/plain";
            }

            // start json object
            Response.Write("{\"keepalive\":\"");
            Response.Flush();

            Task[] tasks = new Task[2];
            tasks[0] = Task.Factory.StartNew(() => DoKeepAlive());
            tasks[1] = Task.Factory.StartNew(() => DoUpload(model, videoFile));
            Task.WaitAll(tasks);

            // end keepalive json property
            Response.Write("\",\"data\":");

            // insert actual response data
            JavaScriptSerializer json = new JavaScriptSerializer();
            Response.Write(json.Serialize(uploadResponse));

            // end json object
            Response.Write("}");

            return "";
        }

        public bool uploadFinished = false;
        public UploadResponseModel uploadResponse = null;

        public void DoUpload(UploadModel model, HttpPostedFileBase videoFile)
        {
            // do upload to 3rd party
            MyServiceClient c = new MyServiceClient();
            uploadResponse = c.UploadVideo(model, videoFile);
            uploadFinished = true;
        }

        public void DoKeepAlive()
        {
            // send . every 10 seconds
            while (!uploadFinished)
            {
                Response.Write(".");
                Response.Flush();
                Thread.Sleep(10000);
            }
        }
    }
}

此解决方案依赖.Net 4来执行异步操作。如果您有.Net 4.5,则有更新的方法可以在不依赖于AsyncController类的mvc控制器中执行异步。

这个网站很有用,并解释了如何在各种版本的.Net框架中在asp.net mvc中进行异步操作:

http://dotnet.dzone.com/news/net-zone-evolution

答案 1 :(得分:1)

太糟糕了,您无法调整站点的负载均衡器配置。

我认为你想做一个javascript keep-alive。

例如:

(function poll(){
$.ajax({ url: "server", success: function(data){
    //Update your dashboard gauge
    salesGauge.setValue(data.value);

}, dataType: "json", complete: poll, timeout: 30000 });
})();

参考文献:

related question

jQuery example