0

Есть несколько вопросов, которые касаются работы асинхронного контроллера, но никто не имеет отношения к тому, что мне нужно. надеюсь, кто-то уже это сделал и может сказать мне, что я делаю что-то неправильно.AsyncController, используемый для запуска консольного приложения

У меня есть комбинация веб-приложения, которое занимается настройкой задач и консольной консольной программой, которая занимается запуском настроенных задач. Я хотел иметь возможность запускать задачи из веб-приложения, нажав кнопку, на которой элемент управления немедленно возвращается пользователю, а задача выполняется в фоновом режиме. AsyncController кажется идеальным сочетанием. Оба приложения обращаются к одной базе данных с использованием EF6, инъекции зависимостей Unity и SQL Server 2012. Веб-интерфейс предназначен для .NET 4.5 на MVC4.

Я могу запустить консольное приложение отлично, без заминки. Я также могу запустить запуск из веб-интерфейса с помощью кода ниже. Единственная проблема заключается в том, что при запуске через веб-приложение задача будет выполняться до точки (я могу видеть ее в журналах (Nlog)), но она прекращает выполнение до тех пор, пока я не перестрою решение. Решение содержит оба приложения, которые также заменят. exe запускается. Когда я запускаю консольное приложение, я не получаю никаких пауз.

Это мой первый опыт использования Task, и я тоже немного застенчив с классом Process. Пожалуйста, не будьте слишком суровыми, если я делаю что-то невероятно глупое.

Вот код для контроллера:

public class TaskRunnerController : AsyncController 
{ 
    private readonly ITaskProcessService _taskProcessService; 
    private readonly IAuthenticationContext _context; 
    private readonly IServiceBase<Task> _taskService; 

    public TaskRunnerController(ITaskProcessService taskProcessService, 
     IAuthenticationContext context, 
     IServiceBase<Task> taskService) 
    { 
     _taskProcessService = taskProcessService; 
     _context = context; 
     _taskService = taskService; 
    } 

    private string TaskRunnerExe 
    { 
     get 
     { 
      var setting = ConfigurationManager.AppSettings["TaskRunner.Exe"]; 
      Guard.Against<ConfigurationErrorsException>(string.IsNullOrEmpty(setting), "Missing configuration setting: TaskRunner.Exe"); 
      return setting; 
     } 
    } 

    [CustomAuthorize(typeof(CanRun))] 
    public ActionResult RunTaskAsync(long id) 
    { 
     var task = _taskService.Find(i => i.TaskId == id); 
     Guard.AgainstLoad(task, id); 
     var fileInfo = new FileInfo(TaskRunnerExe); 
     Guard.Against<ConfigurationErrorsException>(!fileInfo.Exists, "TaskRunner could not be found at specified location: {0}", TaskRunnerExe); 
     var taskProcess = _taskProcessService.Schedule(task, _context.Principal.Identifier); 
     AsyncManager.OutstandingOperations.Increment(); 
     System.Threading.Tasks.Task.Factory.StartNew(() => 
     { 
      ProcessStartInfo info = new ProcessStartInfo(fileInfo.FullName, 
       string.Format("{0} {1}", task.TaskId, taskProcess.TaskProcessId)); 
      info.UseShellExecute = false; 
      info.RedirectStandardInput = true; 
      info.RedirectStandardOutput = true; 
      info.CreateNoWindow = true; 
      var process = new Process { StartInfo = info, EnableRaisingEvents = true }; 
      process.Exited += (sender, e) => 
      { 
       AsyncManager.OutstandingOperations.Decrement(); 
      }; 
      process.Start(); 
     }); 
     if (_context.Principal.HasPermission<CanViewList>()) 
      return RedirectToAction("Index", "Tasks"); 
     return RedirectToAction("Index", "Home"); 
    } 

    public ActionResult RunTaskProgress() 
    { 
     return View(); 
    } 

    public ActionResult RunTaskCompleted() 
    { 
     return Content("completed", "text/plain"); 
    } 
} 

Зависимости:

  • taskProcessService: хранилище для каждого события задачи выполняется
  • контекста: хранит информацию о текущем пользователе
  • taskService : репозиторий для задач

Консольное приложение (.exe) выходит, когда оно полностью завершено. Как я уже упоминал, при вызове через веб-приложение задача заканчивается только после того, как я перестрою приложение - на данный момент он делает все, что нужно - кажется, что он работал все время, он просто прекратил ведение журнала или отчет в какой-то момент в процессе.

Возможно, это важно. У меня была другая попытка без контроллера Async, но с той же настройкой - запустить Process, завернутый в задачу, которая имела тот же конечный эффект. Я думал, что процесс был убит, когда основной поток был возвращен в пул, поэтому я попробовал AsyncController.

Если я открываю диспетчер задач, я вижу, что процесс exe сидит там без дела. Приложение регистрирует прогресс до точки, но затем просто сидит там. Это проблема с VS? Я использую VS2012.

Неправильно ли я превратить процесс в задачу? Есть ли способ запустить исполняемый файл непосредственно через класс Task и класс Action?

Большое спасибо за понимание.

+0

Только после мысли: у меня создалось впечатление, что AsyncController должен служить именно этой цели - ударом долгого процесса и возвращает поток запросов обратно в пул. Когда процесс завершен, из пула берется другой поток для обработки ответа. Разве это не то, что происходит? –

+0

Вид. Вы все еще должны ждать завершения процесса. Вы не можете завершить запрос, иначе дерево задач будет очищено. Поток возвращается в пул, но вы все еще ожидаете завершения задачи. –

ответ

0

Более чем вероятно, что приложение прекращается, потому что рабочий процесс завершается. IIS завершает любые потоки или дочерние процессы, выполняемые под потоком запросов после его завершения.

Как таковое, это просто нецелесообразно делать то, что вы делаете. Вы можете перенести консольное приложение на задачу расписания, а затем запустить запланированную задачу из веб-приложения.

+0

Спасибо за понимание Эрика. Именно так я и думал. Я буду искать выполнение этих задач через службу Windows в какой-то момент, но пока я просто хотел, чтобы это работало. Что вызывает недоумение, хотя я вижу процесс в диспетчере задач (не будучи убитым) - идентификатор процесса регистрируется, когда он запускается, поэтому я могу сказать, что он правильный. Является ли основной поток при выходе, просто убивая поток задачи, но не завернутый процесс? Как сказано, при восстановлении процесс возобновится и закончен, как обычно. –

0

Обновление по этому вопросу. Я установил, что exe (консольное приложение), которое запускается процессом, действительно работает как обычно в фоновом режиме. Однако по какой-то причине он перестает писать стандартный поток вывода, когда по какой-либо причине он перенаправляется. Я обновил запущенное консольное приложение, чтобы он добавлял журналы непосредственно к задаче в базе данных по мере ее продвижения, и это работает нормально. Я могу отслеживать ход выполнения задачи на веб-сайте в режиме реального времени.

Я также проверил отсутствие утечек памяти (как консольное приложение, так и веб-сайт - управляемый код). Как только exe будет закончен, он будет удален из списка процессов, как я ожидал.

Точка, вышеприведенный код работает, но я все еще не уверен, почему стандартный вывод не записывается. Это может быть из-за того, что внутри консольного приложения я использую зависимую инъекцию Nlog для записи в Консоль через ConsoleTarget.