Yii Php Выполнение асинхронного фонового запроса

Привет я пытаюсь выполнить ДЛИННЫЙ БЕГ запрос (действие) в фоновом режиме.

function actionRequest($id){

//execute very long process here in background but continue redirect

Yii::app()->user->setFlash('success', "Currently processing your request you may check it from time to time.");
$this->redirect(array('index', 'id'=>$id));
}

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

Итак, я хочу немедленно вернуться на страницу уведомив пользователя о том, что его / ее запрос обрабатывается, в то время как он все еще может просматривать и выполнять другие действия в приложении, он / она может затем вернуться на страницу и увидеть, что его / ее запрос был обработан.

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

Аналогичное расширение runactions обещает то же самое, но я даже не мог заставить его работать, он говорит, что «касается URL», как огонь и забыл работу, но не работает.

Я также пытался изучить службы очередей сообщений, такие как Gearman, RabbitMQ, но на самом деле очень техническая, я даже не смог установить Gearman на свою машину с Windows, так что «фермерские» услуги мне не подойдут. Некоторые ответы на фоновую обработку включают CRON и AJAX, но это звучит не слишком хорошо, а также множество проблем.

Есть ли другой способ обойти асинхронную фоновую обработку? Я действительно стремился к этому, и я действительно не ищу продвинутых / сложных решений, таких как «отработка работы на нескольких машинах» и тому подобное. Спасибо Большое!

3

Решение

Если вы хотите иметь возможность запускать асинхронные задания через Yii, у вас может не быть выбора, кроме как поболтать с некоторым AJAX, чтобы получить статус задания асинхронно. Вот руководящие принципы высокого уровня, которые работали для меня. Надеюсь, это поможет вам в некотором роде!

Для запуска фоновых заданий вам понадобится компонент консоли Yii. В каталоге / protected / commands создайте копию вашего веб-контроллера, в которой есть ваш actionRequest () (например, /protected/commands/BulkCommand.php).

Это должно позволить вам зайти в вашу / защищенную папку и запустить yiic bulk request,

Помните, что если вы ранее не создавали консольное приложение, вам необходимо настроить его конфигурацию, аналогичную настройке веб-приложения. Прямая копия /protected/config/main.php в /protected/config/console.php должна выполнять 90% работы.

Что сработало для меня, так это использование комбинации двух расширений: CConsole а также TConsoleRunner. TConsoleRunner использует popen для запуска сценариев оболочки, которые работали для меня в Windows и Ubuntu. Я просто слил код run () в CConsole следующим образом:

public function popen($shell, $redirectOutput = '')
{
$shell = $this->resolveCommandLine($shell, false, $redirectOutput);
$ret = self::RETURN_CODE_SUCCESS;
if (!$this->displayCommands) {
ob_start();
}

if ($this->isWindows()) {
pclose(popen('start /b '.$shell, 'r'));
}
else {
pclose(popen($shell.' > /dev/null &', 'r'));
}

if (!$this->displayCommands) {
ob_end_clean();
}
return $ret;
}

protected function isWindows()
{
if(PHP_OS == 'WINNT' || PHP_OS == 'WIN32')
return true;
else
return false;
}

После этого я изменил runCommand () в CConsole следующим образом:

public function runCommand($command, $args, $async = false, &$outputLines = null, $executor = 'popen')
{
...
switch ($executor) {
...
case 'popen':
return $this->popen($shell);
...
}
}

С установленным выше, теперь вы можете использовать следующий фрагмент кода для вызова yiic bulk request мы создали ранее.

$console = new CConsole();
$console->runCommand('bulk request', array(
'--arg1="argument"',
'--arg2="argument"',
'--arg3="argument"',
));

Вы вставили бы это в ваш оригинальный actionRequest ().

К сожалению, я не уверен, какую работу выполняет ваш массовый запрос. Для себя я собирал целую кучу файлов и помещал их в папку. Я знал, сколько файлов я ожидал, так что я мог легко создать действие контроллера, которое проверяет, сколько файлов было создано до сих пор и дает% статуса в виде простого деления.

1

Другие решения

Других решений пока нет …