Я хочу разработать такую систему, чтобы пользователи могли отправлять файлы. После того, как они отправят файл, я запусту несколько скриптов с файлами. Я хочу, чтобы эти файлы запускались по порядку, поэтому я хочу поддерживать очередь запросов. Как я могу сделать это с php? Есть ли какая-нибудь библиотека с открытым исходным кодом для этого?
Спасибо!
Я бы использовал базу данных ..
я хотел бы использовать Redis. Redis — это сверхбыстрое хранилище значений ключей; обычно его время отклика составляет двузначные микросекунды. (10 — 99 микросекунд)
Транзакции Redis являются атомарными (транзакции либо случаются, либо нет), и вы можете постоянно выполнять задание без использования cron.
Чтобы использовать Redis с PHP, вы можете использовать Predis.
Как только Redis установлен и Predis настроен для работы с вашим скриптом, после загрузки файла я сделаю что-то вроде этого:
// 'hostname' and 'port' is the hostname and the port
// where Redis is installed and listening to.
$client = new Predis\Client('tcp://hostname:port');
// assuming the path to the file is stored in $pathToFile
$client->lpush('queue:files', $pathToFile);
тогда скрипт, который должен работать с файлами, просто должен сделать что-то вроде:
$client = new Predis\Client('tcp://hostname:port');
// assuming the path to the file is stored in $pathToFile
while(true){
$pathToFile = $client->rpop('queue:files');
if(!$pathToFile) {
// list is empty, so move on.
continue;
}
// there was something in the list, do whatever you need to do with it.
// if there's an exception or an error, you can always use break; or exit; to terminate the loop.
}
Примите во внимание, что PHP имеет тенденцию использовать много памяти, поэтому я бы либо явно собирал мусор (через gc_enable()
а также gc_collect_cycles()
а также unset()
переменные, как вы идете).
Кроме того, вы можете использовать программное обеспечение, как supervisord
чтобы запустить этот скрипт всего один раз, и как только он закончится, запустите его снова.
В общем, я бы не использовал базу данных и cron для реализации очередей. Это может привести к серьезным проблемам.
Предположим, например, что вы используете таблицу в качестве очереди.
При первом запуске ваш скрипт извлекает задание из базы данных и начинает делать свое дело.
Затем по какой-то причине ваш сценарий запускается дольше, и снова запускается задание cron, и теперь у вас есть 2 сценария, работающих с одним файлом. Это может не иметь никаких последствий или иметь серьезные последствия. Это зависит от того, что на самом деле делает ваше приложение.
Так что, если вы не работаете с очень маленьким набором данных и не знаете наверняка, что ваш cronjob закончится до запуска предыдущего скрипта, и не будет никаких коллизий, тогда у вас все будет хорошо. В противном случае, держитесь подальше от этого подхода.
Сторонняя библиотека? Слишком просто, чтобы нужна целая библиотека. Вы можете использовать Redis (см. Ответ AlanChavez), если вы хотите тратить время и ресурсы, а затем должны быть обеспокоены сборкой мусора, когда реальное решение не состоит в том, чтобы изначально вносить мусор в смесь.
Ваша очередь представляет собой текстовый файл. Когда файл загружен, имя файла добавляется в очередь.
$q= fopen('queue.txt','a');
'a'
режим важен. Он автоматически перемещает указатель записи в конец файла для добавления записи. Но причина, по которой это важно, заключается в том, что если файл не существует, создается новый.
fwrite($q,"$filename\n");
fclose($q);
При одновременной записи в этот файл дополнения ОС с ошибкой разрешает конфликт. Нет необходимости в блокировке файлов, совместной многозадачности или обработке транзакций.
Когда ваш сценарий, который обрабатывает очередь, начинает выполняться, он переименовывает текущую очередь в рабочую очередь.
if(!file_exists('q.txt')){
if(!file_exists('queue.txt')){exit;}
rename('queue.txt','q.txt');
$q = fopen(`q.txt`,'r');
while (($filename = fgets($q, 4096)) !== false) {
process($filename);
}
fclose($q);
unlink('q.txt');
}
else{
echo 'Houston, we have a problem';
}
Теперь вы понимаете, почему 'a'
Режим был важен. Мы переименовываем очередь, и когда происходит следующая загрузка, файл queue.txt создается автоматически.
Если файл записывается в том виде, в котором он переименовывается, ОС выполнит его сортировку без ошибок. Переименование настолько быстрое, что вероятность одновременной записи астрономически мала. И это основная функция ОС, позволяющая разобраться в конфликтах файловой системы. Нет необходимости в блокировке файлов, совместной многозадачности или обработке транзакций.
Это пуленепробиваемый метод, которым я пользуюсь много лет.
Замените цитату Apollo 13 процедурой восстановления после ошибки. Если q.txt существует, предыдущая обработка не была успешно завершена.
Это было слишком просто.
Потому что это так просто и у нас достаточно памяти, потому что мы такие эффективные: давайте повеселимся.
Давайте посмотрим, выполняется ли запись в очередь быстрее, чем «сверхбыстрый» Redis от AlanChavez с его ответом, состоящим только из двузначных миллисекунд.
Время в секундах для добавления имени файла в очередь = 0,000014537 или 14,5 мкс. Немного лучше, чем «супербыстрое» время отклика Redis 10-99 мс, как минимум на 100 000%.