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

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

问题描述

我遇到了 该线程 已经存在,但我可能需要针对我的情况的其他内容.

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

我有一个返回 ViewResult 的操作,它由客户端的 $.post()

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);
});

控制器:

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();
}

正如评论所暗示的那样,控制器内部有一个很长的任务在运行.(这是一个文档生成模块,可将 PDF 上传到 Azure blob 存储并将指向它的链接返回到视图.)

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.)

这在我的开发机器上运行良好,但是当它在(安全的)Azure 生产环境中运行时,它超时.我已经在各处输入了大量日志条目,结果证明它能够上传文档并返回到控制器(即它到达上面的控制器返回语句).但是,当需要将模型数据返回到视图时,客户端脚本不会回调(即 div 内容不会被结果替换).

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.

如果我在我的 GetFoo() 方法上使用属性 [AsyncTimeout(3600)],那么这个操作永远不会从 UI 调用.

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

任何建议将不胜感激.

推荐答案

问题是 Azure 负载均衡器有自己的超时设置,设置为一分钟.任何超过一分钟的请求都会被终止.没有办法改变这一点.

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.

在 Azure 环境中解决此问题的方法是让一个 ajax 调用启动进程并返回某种进程 ID,然后让客户端轮询另一个 ajax 调用以传入此进程 ID 以查看它是否完整.它可能看起来像这个未经编译和未经测试的代码.在 JavaScript 中:

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);
        }
    });
}

在你的控制器中:

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天全站免登陆