Establecer tiempo de espera para la acción del controlador

Ya he encontrado este hilo , pero podría necesitar algo más para mi situación.

Tengo una acción que devuelve un ViewResult , que es llamado por el cliente $.post()

JavaScript:

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

Controlador:

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

Como lo indica el comentario, hay una tarea larga que se ejecuta dentro del controlador. (Este es un módulo de generación de documentos que carga archivos PDF en el almacenamiento de blobs de Azure y le devuelve un enlace a la Vista).

Esto funciona bien en mi máquina dev, pero cuando se activa en un entorno de producción (seguro) de Azure, se agota el tiempo . He colocado un montón de entradas de registro en todas partes y resulta que puede cargar los documentos y devolverlos al controlador (es decir, llega a la statement de devolución del controlador anterior). Sin embargo, cuando es el momento de devolver los datos del modelo a la Vista, el script del cliente no devuelve la llamada (es decir, el contenido div no se reemplaza con los resultados).

¿Hay alguna manera de prolongar de alguna manera el tiempo de espera de la llamada? Es difícil de reproducir en mi entorno local (no seguro), por lo que una solución definitiva ayudará.

Si uso el atributo [AsyncTimeout(3600)] en mi método GetFoo() , esta acción nunca se llama desde la interfaz de usuario.

Cualquier sugerencia será apreciada.

El problema es que el equilibrador de carga de Azure tiene su propio tiempo de espera establecido en un minuto. Cualquier solicitud que demore más de un minuto se termina . No hay manera de cambiar esto.

La forma de evitar esto en el entorno de Azure es hacer que una llamada ajax inicie el proceso y devuelva algún tipo de ID de proceso y luego haga que el cliente realice otra llamada ajax para pasar esta ID de proceso para ver si está completa. Puede verse algo así como este código no comstackdo y no probado. En 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); } }); } 

Y en tu mando:

 public ViewResult BeginFooProcessing(String fooBar) { if (Request.IsAjaxRequest()) { Guid fooId = Guid.NewGuid(); var result = new FooResult { FooId = fooId, HasFinishedProcessing = false, Uris = new List() }; // 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 Uris; } 

Esperemos que eso te dé un punto de partida.

quieres mirar esto

La respuesta a tu pregunta es: [AsyncTimeout (3600000)]

Ver más aquí Controlador Timeout MVC 3.0

Para usar los controladores Async, su controlador debe heredar de AsyncController:

 public class WebsiteController : AsyncController 

Y luego, cualquier acción que use métodos asíncronos tiene que usar el formato de

 public void ActionNameAsync(int param) public ActionResult ActionNameCompleted(int param) 

Donde ActionName es el nombre de su acción, y en lugar del uso de la función Async

 AsyncManager.OutstandingOperations.Increment(); 

Cada vez que inicie un nuevo método asíncrono y

 AsyncManager.OutstandingOperations.Decrement(); 

cuando finalice el método, una vez que se hayan completado todas las operaciones pendientes, se moverá a la función Completada (asegúrese de especificar los parámetros que necesita para la función completada en la función asíncrona para que sepa qué pasar)

 AsyncManager.Parameters["param"] = "my name"; 

Entonces, usar el atributo AsyncTimeout afectaría realmente a la función. No estoy seguro de qué sucede si intenta aplicar ese atributo a una acción que no está en un controlador asíncrono.

Estos cambios no requerirían cambiar ninguna de las referencias a la acción en el javascript y qué no, ya que simplemente solicitaría ‘ActionName’ y vería si existía la versión de configuración Async / Completed y, en caso contrario, ‘ Busco solo esa acción normal y uso lo que encuentre.