Фоновый процесс для импорта данных в PHP - PullRequest
0 голосов
/ 03 октября 2011

Подробности

Когда пользователь впервые входит в мое приложение, мне нужно импортировать все продукты их магазина из API, это может быть где угодно от 10 до 11 000 товаров. Поэтому я думаю, что мне нужно сообщить пользователю, что мы импортируем его продукты, и по электронной почте, когда мы закончим.

Вопросы

Как лучше всего импортировать эти данные, не требуя от пользователя оставаться на странице?
Должен ли я идти по маршруту pcntl_fork?
Будет ли system стиль фоновых задач лучше?

Ответы [ 2 ]

3 голосов
/ 03 октября 2011

AFAIK нет способа pcntl_fork() из процесса веб-сервера, вы можете сделать это только из командной строки. Однако вы можете запустить дочерний процесс, используя exec() (или аналогичный), который продолжит выполняться после вашего завершения.

Я не знаю, насколько это "правильно", но я бы сделал что-то вроде этого:

upload.php - Заставьте пользователя загружать список своих товаров в любом формате. Я предполагаю, что вы знаете, как это сделать, и не буду включать никакого кода - если вы хотите пример, дайте мне знать.

store.php - форма загрузки отправляется в этот файл:

// Make sure a file was uploaded and you have the user's ID
if (!isset($_FILES['file'],$_POST['userId']))
  exit('No file uploaded or bad user ID');

// Make sure the upload was successful
if ($_FILES['file']['error'])
  exit('File uploaded with error code '.$_FILES['file']['error']);

// Generate a temp name and store the file for processing
$tmpname = microtime(TRUE).'.tmp';
$tmppath = '/tmp/'; // ...or wherever you want to temporarily store the file
if (!move_uploaded_file($_FILES['file']['tmp_name'],$tmppath.$tmpname))
  exit('Could not store file for processing');

// Start an import process, then display a message to the user
// The ' > /dev/null &' is required here - it let's you start the process asynchronously
exec("php import.php \"{$_POST['userId']}\" \"$tmppath$tmpname\" > /dev/null &");

// On Windows you can do this to start an asynchronous process instead:
//$WshShell = new COM("WScript.Shell");
//$oExec = $WshShell->Run("php import.php \"{$_POST['userId']}\" \"$tmppath$tmpname\"", 0, false);

exit("I'm importing your data - I'll email you when I've done it");

import.php - обрабатывает импорт и отправляет электронное письмо

// Make sure the required command line arguments were passed and make sense
if (!isset($argv[1],$argv[2]) || !file_exists($argv[2])) {
  // handle improper calls here
}

// Connect to DB here and get user details based on the username (passed in $argv[1])

// Do the import (pseudocode-ish)
$wasSuccessful = parse_import_data($argv[2]);

if ($wasSuccessful) {
  // send the user an email
} else {
  // handle import errors here
}

// Delete the file
unlink($argv[2]);

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

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

1 голос
/ 03 октября 2011

Я думаю, что "стандартный" способ сделать это в PHP - запускать cron каждые пять минут или около того, чтобы проверять очередь ожидающих импорт.

Таким образом, ваш пользователь входит в систему, частью процесса входа является добавление их в вашу таблицу «pending_import» (или, как вы решите, сохранить очередь импорта). Затем в следующий раз, когда cron сработает, он позаботится о текущем содержимом вашей очереди.

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