Вообще более-менее правильный подход:
- пользователь отправляет запрос на сервер
- сервер добавляет задачу в очередь
- обработчик-демон берет задачу и делает ее
По поводу отслеживания прогресса все чуть интереснее. Есть как минимум 4 варианта реализации:
- пулинг - когда периодически мы шлем ajax запрос на сервер и спрашиваем сколько там сделано
- лонг-пулинг - оптимизация первого варианта, при которой запрос не сразу отваливается, а отваливается либо по таймауту (скажем прошло 10 секунд) или же изменилось состояние и нам нужно об этом уведомить пользователя. Как только соединение отвалилось мы обрабатываем что там нам пришло или не пришло и повторяем запрос. Профит - реалтайм нотификация, то есть как-только у нас появилась свежая информация мы можем ее получить.
- Server-sent events, когда запрос отдается нам по кускам с разделителями. Каждый кусок отдается тогда, когда что-то на сервере поменялось. Профит тот же что и в варианте с лонг полингом только не надо разрывать соединение. Но есть куча нюансов (скажем с Apache это не прокатит) и мало кто так делает.
- web sockets - реалтайм, полнодуплексный, удобный вариант, но нужно заводить отдельный демон.
Самый простой вариант - простой пулинг, в вашем случае реалтайм вам не нужен, достаточно раз в 10 секунд спрашивать сервер что там как. В этом случае обработчик очереди (или дочерний процесс или еще кто) может записывать в кэш текущий статус джобы, и вы можете получать ее по идентификатору. в качестве хранилища можно использовать redis или memcache, в этом плане они идеальны.