Как спроектировать бэкэнд для помещения запросов в очередь?

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

Спасибо!

0

Решение

Я бы использовал базу данных ..

  1. Когда пользователь отправляет файл, он добавляет ссылку на свое местоположение в файловой системе в базу данных.
  2. У вас есть запущенный cron, который проверяет новые заявки и обрабатывает их по порядку, когда это делается, он помечает его как обработанный в базе данных.
-1

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

я хотел бы использовать 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 закончится до запуска предыдущего скрипта, и не будет никаких коллизий, тогда у вас все будет хорошо. В противном случае, держитесь подальше от этого подхода.

-1

Сторонняя библиотека? Слишком просто, чтобы нужна целая библиотека. Вы можете использовать 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%.

-2