Как бы ASP. NET приложение MVC3 вызывало некоторый код, когда действие контроллера отменяется по тайм-ауту клиента? - PullRequest
1 голос
/ 27 января 2020

Существует приложение ASP. NET MVC3, в котором некоторые действия контроллера используют внешний механизм для обработки входных данных. Входные данные сначала сохраняются во временный файл, а затем запускается внешняя программа, и путь к временному файлу передается в командной строке. Это делается с использованием System.Diagnostics.Process класса.

Внешняя программа обычно завершается быстро - раньше, чем через одну секунду после ее запуска, так что нет проблем, просто дождитесь ее завершения с помощью Process.WaitForProcessExit() и утилизируйте Process объект.

Становится труднее, если внешняя программа зависает и не завершает работу своевременно. Это происходит очень-очень редко, но когда это происходит, то Process.WaitForProcessExit() тоже зависает, и действие контроллера выполняется некоторое время, но затем происходит тайм-аут клиента и действие контроллера отменяется, но я не могу найти способ вызвать принудительное завершение внешняя программа. Я мог бы использовать Process.Kill(), но мне нужно подключить этот вызов куда-нибудь так, чтобы он вызывался при отмене действия контроллера из-за тайм-аута клиента.

Я попытался переопределить Controller.OnException(), но похоже, что это не вызывается в этом сценарии.

Как можно ASP. NET код MVC3 изменить таким образом, чтобы он вызывал некоторый пользовательский код (например, завершение внешней программы) при возникновении тайм-аута клиента?

1 Ответ

1 голос
/ 27 января 2020

Я проверил решение по комментариям на основе Task - это полезно, когда у вас есть операция блокировки. Вы можете избежать блокировки вызова WaitForProcessExit() и создать более простое решение.

Решение находится в форме оболочки.

public enum SafeProcessState { Exit = 1, Killed = 2 }

public class SafeProcess
{
    private readonly Process process;
    private readonly Func<bool> killPredicate;

    public SafeProcess(Func<bool> killPredicate, Process process)
    {
        this.killPredicate = killPredicate;
        this.process = process;
    }

    public async Task<SafeProcessState> WaitAsync()
    {
        var state = SafeProcessState.Exit;

        while (true) 
        {
            await Task.Delay(100);
            if (this.killPredicate())
            {
                state = SafeProcessState.Killed;
                if (this.process.HasExited == false)
                {
                    this.process.Kill();
                }
                break;
            }
            else if (this.process.HasExited) 
            {
                break;
            }
        }

        return state;
    }
}

Вот как вы можете использовать его в ASP NET MVC action (Not. NET CORE);

public async ...... ActionName()
{
  var process = Process.Start("....");
  var wrapper = new SafeProcess(() => HttpContext.Current.Response.IsClientConnected == false, process);

 var state = await wrapper.WaitAsync();
}

В основном он ожидает (проверяя каждые 100 мс), что процесс завершается, или клиент отключается и возвращает информацию о выходе. причина - Exit или Killed.
Убивает процесс, если пользователь отключился.


Использование async / await Task.Delay гарантирует, что мы освободим поток выполнения, и в течение 100 мс это делается исключительно из соображений производительности.

ПРИМЕЧАНИЕ : Вы можете получить в сценарий убийства уже вышедшего процесса, который вызовет исключение (у вас есть параллелизм между процессом и вашим действием asp net). Вам потребуется некоторая синхронизация между выполнением процесса и .Kill() ... или вы можете заключить вызов в try / catch.
Если вы выберете сценарий try / catch Забыли, обязательно запишите ситуацию.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...