设置超时时间控制器动作 [英] Set Timeout For Controller Action

查看:799
本文介绍了设置超时时间控制器动作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我所遇到的<一个href=\"http://stackoverflow.com/questions/579523/how-do-i-set-the-request-timeout-for-one-controller-action-in-an-asp-net-mvc-appl\">this螺纹了,但我可能需要别的东西我的情况。

我有一个返回操作的的ViewResult ,这是由客户端的 $。员额() <叫/ p>

JavaScript的:

  VAR链接= + foobar的'Foobar的调用getFoo =?;VAR jqxhr = $。员额(链接功能(响应){
    $('#myDiv')replaceWith(响应)。
});

控制器:

 公开的ViewResult的getFoo(字符串FOOBAR)
{
    如果(Request.IsAjaxRequest())
    {
        //执行一个可笑的长期任务(〜12分钟)
        //算法:1)在Azure Blob存储下载文件
        // 2)更新每个文件
        // 3)重新上传到Blob存储
        // 4)返回的URI列表将被显示到UI
        返回视图(MyFooView的数据);
    }
    抛出新的InvalidOperationException异常();
}

由于注释暗示,有控制器内运行的长期任务。 (这是一个文档生成模块,上传PDF文件,以在Azure Blob存储,并返回一个链接来查看。)

这是工作的罚款在我的dev的机器,但是,当它在一个(安全)的Azure生产环境上线,它的超时的。我已经把在许多到处日志条目和事实证明,它是能够上传的文件,并返回到控制器(即,它到达该控制器返回语句上文)。然而,当它是时候该模型数据返回给视图,客户端脚本不叫回来(即 DIV 内容不会被替换的结果)

有没有办法以某种方式延长的呼叫超时?这是很难复制在我的(不安全的)当地的环境,使的最终解决方法会有所帮助。

如果我使用属性 [AsyncTimeout(3600)] 我的的getFoo()方法,那么这个动作永远不会被从UI调用。

任何建议将AP preciated。


解决方案

的问题是,在Azure负载平衡器有它自己的超时被设置为一分钟。这需要更长的时间不到一分钟的请求被终止。有没有办法改变这一点。

在Azure的环境中解决这个问题的办法是有一个Ajax调用启动进程并返回某种进程ID,然后在客户端轮询其他Ajax调用传递这一进程ID,看它是否是完整的。它可能看起来像这样未编译的和未经考验code。在JavaScript:

  VAR链接='Foobar的BeginFooProcessing ='+ foobar的;VAR jqxhr = $。员额(链接功能(响应){
    VAR finishedlink ='CheckFooFinished fooId ='+响应;    //检查,看看我们在1秒钟内就完蛋了
    的setTimeout(CheckIfFinishedYet('+ finishedlink +'),1000);
});功能CheckIfFinishedYet(finishedlink){
    VAR响应= $。员额(finishedlink,函数(响应){
        如果(响应== NULL){
            //如果我们没有得到一个结果,然后检查在一秒钟
            的setTimeout(CheckIfFinishedYet('+ finishedlink +'),1000);
        }
        其他{
            //耶,我们已经有了一个结果,所以我们只写出来
            $('#myDiv')replaceWith(响应)。
        }
    });
}

和在你的控制器:

 公开的ViewResult BeginFooProcessing(字符串FOOBAR)
{
    如果(Request.IsAjaxRequest())
    {
        GUID fooId = Guid.NewGuid();        VAR的结果=新FooResult
                        {
                            FooId = fooId,
                            HasFinishedProcessing =假,
                            尤里斯=新的List&LT;串GT;()
                        };        //这需要去持久存储的地方
        //为后续的请求可能不会再回到这个
        // 网络服务器
        result.SaveToADatabaseSomewhere();        System.Threading.Tasks.Task.Factory.StartNew(()=&GT; ProcessFoo(fooId));
        返回视图(MyFooStartView,fooId);
    }
    抛出新的InvalidOperationException异常();
}私人无效ProcessFoo(GUID fooId)
{
    //这里执行你的长期运行的任务    FooResult结果= GetFooResultFromDataBase(fooId);    result.HasFinishedProcessing = TRUE;
    result.Uris = uriListThatWasCalculatedAbove;    result.SaveToADatabaseSomewhere();
}公众的ViewResult CheckFooFinished(GUID fooId)
{
    如果(Request.IsAjaxRequest())
    {
        FooResult结果= GetFooResultFromDataBase(fooId);        如果(result.HasFinishedProcessing)
        {
        //后自己清理
        result.DeleteFromDatabase();            返回视图(MyFooFinishedView,result.Uris);
        }        返回视图(MyFooFinishedView,NULL);    }
    抛出新的InvalidOperationException异常();
}私有类FooResult
{
    公众的Guid FooId {搞定;组; }    公共BOOL HasFinishedProcessing {搞定;组; }    公开名单&LT;串GT;尤里斯;
}

希望这会给你一个起点。

I have come across this thread already, but I might need something else for my situation.

I have an action that returns a ViewResult, which is called by the client's $.post()

JavaScript:

var link = 'GetFoo?fooBar=' + fooBar;

var jqxhr = $.post(link, function (response) {
    $('#myDiv').replaceWith(response);
});

Controller:

public ViewResult GetFoo(String fooBar)
{
    if (Request.IsAjaxRequest())
    {
        // perform a ridiculously long task (~12 minutes)           
        // algorithm: 1) download files from the Azure blob storage
        // 2) update each file
        // 3) reupload to blob storage
        // 4) return a list of URIs to be displayed to the UI
        return View("MyFooView", data);
    }
    throw new InvalidOperationException();
}

As the comment implies, there is long task running inside the Controller. (This is a document generation module that uploads PDFs to the Azure blob storage and returns a link to it to the View.)

This is working fine in my dev machine but when it goes live in a (secure) Azure production environment, it times out. I have put in lots of logging entries everywhere and as it turns out, it is able to upload the documents and return to the controller (i.e. it reaches the controller return statement above). However, when it is time to return the model data to the View, the client script doesn't called back (i.e. the div content doesn't get replaced with the results).

Is there a way to somehow prolong the timeout of the call? It is difficult to reproduce in my (unsecure) local environment so a definitive fix will help.

If I use the attribute [AsyncTimeout(3600)] on my GetFoo() method, then this action never gets called from the UI.

Any suggestions will be appreciated.

解决方案

The problem is that the Azure load balancer has it's own timeout which is set to one minute. Any request that takes longer than a minute gets terminated. There is no way to change this.

The way around this in the Azure environment is to have one ajax call start the process and return some sort of process ID then have the client poll another ajax call to passing in this process ID to see if it's complete. It might looks something like this uncompiled and untested code. In javascript:

var link = 'BeginFooProcessing?fooBar=' + fooBar;

var jqxhr = $.post(link, function (response) {
    var finishedlink = 'CheckFooFinished?fooId=' + response;

    // Check to see if we're finished in 1 second
    setTimeout("CheckIfFinishedYet('" + finishedlink + "')", 1000);
});

function CheckIfFinishedYet(finishedlink) {
    var response = $.post(finishedlink, function (response) {
        if (response == null) {
            // if we didn't get a result, then check in another second
            setTimeout("CheckIfFinishedYet('" + finishedlink + "')", 1000);
        }
        else {
            // Yay, we've got a result so we'll just write it out
            $('#myDiv').replaceWith(response);
        }
    });
}

And in your controller:

public ViewResult BeginFooProcessing(String fooBar)
{
    if (Request.IsAjaxRequest())
    {
        Guid fooId = Guid.NewGuid();

        var result = new FooResult
                        {
                            FooId = fooId,
                            HasFinishedProcessing = false,
                            Uris = new List<string>()
                        };

        // This needs to go to persistent storage somewhere
        // as subsequent requests may not come back to this
        // webserver
        result.SaveToADatabaseSomewhere();

        System.Threading.Tasks.Task.Factory.StartNew(() => ProcessFoo(fooId));


        return View("MyFooStartView", fooId);
    }
    throw new InvalidOperationException();
}

private void ProcessFoo(Guid fooId)
{
    // Perform your long running task here

    FooResult result = GetFooResultFromDataBase(fooId);

    result.HasFinishedProcessing = true;
    result.Uris = uriListThatWasCalculatedAbove;

    result.SaveToADatabaseSomewhere();
}

public ViewResult CheckFooFinished(Guid fooId)
{
    if (Request.IsAjaxRequest())
    {
        FooResult result = GetFooResultFromDataBase(fooId);

        if (result.HasFinishedProcessing)
        {
        // Clean up after ourselves
        result.DeleteFromDatabase();

            return View("MyFooFinishedView", result.Uris);
        }

        return View("MyFooFinishedView", null);

    }
    throw new InvalidOperationException();
}

private class FooResult
{
    public Guid FooId { get; set; }

    public bool HasFinishedProcessing { get; set; }

    public List<string> Uris;
}

Hopefully that will give you a starting point.

这篇关于设置超时时间控制器动作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆