У меня есть небольшой скрипт, который обновляет базу данных. В настоящее время требуется около минуты, но время будет расти по мере роста базы данных. Я хочу предоставлять обновления пользователю, когда скрипт работает, чтобы они знали, что статус скрипта и что он все еще продолжается. Я реализовал Server-Side-Events, и пока он работает, ни одно из обновлений не публикуется на веб-сайте до тех пор, пока скрипт не будет полностью завершен.сервер отправил события, не обновляемые до завершения сценария
Я могу загрузить весь файл сценария, но вот соответствующие части.
Во-первых, в начале скрипта я проверяю, чтобы увидеть, если скрипт запускается из командной строки, и если я не посылать заголовки, как показано ниже:
$cli = (PHP_SAPI === 'cli') ? 1 : 0;
if(!$cli){
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
}
Вот моя функция, чтобы отправить sse_message при вызове
function sse_message($type, $message, $progress=0)
{
$d = array("type" => $type, "msg" => $message , "progress" => $progress);
$id = time();
echo "id: $id" . PHP_EOL;
echo "data: " . json_encode($d) . PHP_EOL;
echo PHP_EOL;
ob_flush();
flush();
}
И, наконец, вот мой Javascript реализация слушателя:
if(typeof(EventSource) !== "undefined"){
source = new EventSource("../priv3/script/prowip_process.php");
source.addEventListener("message", function(e)
{
var result = JSON.parse(e.data);
switch(result.type){
case "update":
if(result.msg != "")
document.getElementById("prowip_status").value += "\n[INFO]: "+result.msg;
document.getElementById("prowip_progress").value = result.progress;
break;
case "success":
document.getElementById("prowip_status").value += "\n[COMPLETED]:"+result.msg;
document.getElementById("prowip_progress").value = 100;
document.getElementById("button_prowip_exit").disabled = false;
source.close();
break;
case "error":
document.getElementById("prowip_status").value += "\n[ERROR]: "+result.msg;
document.getElementById("button_prowip_exit").disabled = false;
source.close();
break;
}
}, false);
}
else{
document.getElementById("prowip_status").value += "\n\n[ERROR]: Your browser does not support server-sent events. Please upgrade your browser or use a different browser for this function. Please note this script will not work with Internet Explorer."
document.getElementById("button_prowip_exit").disabled = false;
}
Снова - все работает отлично, за исключением того, что во время процесса сценария не происходит никаких обновлений, а затем, когда он заканчивает все сообщения и индикатор выполнения, обновляется.
Я пробовал это в нескольких браузерах, компьютерах и т. Д., Но ни одно обновление на веб-странице не происходит до тех пор, пока не будет выполнен весь сценарий.
Любая помощь или комментарии были бы весьма признательны. Благодарю.
EDITED 4/3/2015 К POST больше кода в соответствии с просьбой
Эти 3 функции вызывают sse_message или просто эхо для CLI.
function show_error($cli, $message)
{
if ($cli)
echo $message."\n";
else
sse_message("error", $message);
}
function show_message($cli, $message, $progress)
{
if ($cli)
echo $message."[".$progress."%]\n";
else
sse_message("update", $message, $progress);
}
function show_success($cli, $message)
{
if ($cli)
echo $message."[100%]\n";
else
sse_message("success", $message);
}
Вот скрепка из основной функции, которая показывает, как эти функции называются:
foreach ($projects as $number => $project) {
$cn = strtok($number, ".");
$pn = strtok(".");
$wipover = $project['wip'] - $project['wip30'] - $project['wip60'] - $project['wip90'];
$arover = $project['ar'] - $project['ar30'] - $project['ar60'] - $project['ar90'];
$process_counter++;
if($process_counter >= $check){
$progress+=5;
$check += intval ($counter/16);
show_message($cli,"",$progress);
}
if(($project['empty']==1) and ($project['wip']==0) and ($project['ar']==0)){
//Do nothing...
}
else{
$write_counter++;
$update_query = "update projects set wip='{$project['wip']}', wip30='{$project['wip30']}', wip60='{$project['wip60']}', wip90='{$project['wip90']}', wipover='$wipover', ar='{$project['ar']}', ar30='{$project['ar30']}', ar60='{$project['ar60']}', ar90='{$project['ar90']}', arover='$arover' where client_num='$cn' and new_num='$pn'";
if(! $db->query($update_query)){
show_error($cli, "ERROR - update query: [$update_query] returned error: [".$db->error."]", $progress);
}
}
}
Можете ли вы показать основной цикл (т. Е. Часть скрипта PHP, которая вызывает 'sse_message')? Если вы установите для своей версии CLI также вызов 'sse_message()', сколько раз она будет вызвана во время обработки вашей минуты, когда она запускается из командной строки? –
У меня есть 3 простых функции, которые вызывается в зависимости от типа сообщения, поэтому версия CLI не вызывает sse_message и вместо этого использует экранное эхо. Я отправил эти функции в исходное сообщение.Затем основной цикл вызывает одну из этих трех функций. Я опубликовал клип этого процесса. Я могу опубликовать всю функцию, если это будет полезно. Вероятно, sse_message называется около 30 раз. –
Все кажется разумным, не так ли. Если вы посмотрите в консоли разработчика вашего браузера, вкладке сети, видите ли вы, что полученные байты постепенно увеличиваются. Или вы видите 0 полученных байтов, затем все байты принимаются в конце? Мое предположение - последнее, и кеширование происходит на стороне сервера (или на промежуточном кэшировании или прокси-сервере). Вы используете Apache и обычный php-модуль apache? –