HTTP 응답을 보낸 후 PHP 실행 계속
어떻게 하면 PHP 5.2(apache mod_php로 실행)가 클라이언트에 완전한 HTTP 응답을 보낸 다음 1분 동안 작업을 계속 실행할 수 있습니까?
긴 이야기:
저는 긴 데이터베이스 요청을 실행하고 이메일을 보내야 하는 PHP 스크립트를 가지고 있는데, 실행하는 데 45초에서 60초가 걸립니다.이 스크립트는 제어할 수 없는 응용 프로그램에서 호출됩니다.PHP 스크립트에서 받은 오류 메시지(대부분 유효하지 않은 매개 변수 오류)를 보고하기 위해 응용 프로그램이 필요합니다.
애플리케이션의 타임아웃 지연 시간이 45초 미만이므로(정확한 값을 알 수 없음) PHP 스크립트의 모든 실행을 오류로 등록합니다.따라서, 나는 PHP가 가능한 한 빨리 전체 HTTP 응답을 클라이언트에 보내고(이상적으로, 입력 매개 변수가 검증되는 즉시) 데이터베이스와 이메일 처리를 실행해야 합니다.
mod_php를 실행하고 pcntl_fork
사용할 수 없습니다.으로써 이 할 수 .cron
더 짧은 해결책을 찾고 있어요
"특수 스크립트" 도구 상자에 이 스니펫이 있었는데, (그 당시에는 클라우드가 흔하지 않았습니다) 그래서 이 스니펫을 검색하다가 이 질문을 떠올렸고, 이 스니펫이 없어진 것을 보고 깜짝 놀라 더 검색하고 다시 게시했습니다.
<?php
ob_end_clean();
header("Connection: close");
ignore_user_abort(); // optional
ob_start();
echo ('Text the user will see');
$size = ob_get_length();
header("Content-Length: $size");
ob_end_flush(); // Strange behaviour, will not work
flush(); // Unless both are called !
session_write_close(); // Added a line suggested in the comment
// Do processing here
sleep(30);
echo('Text user will never see');
?>
저는 실제로 그것을 사용하는 곳이 거의 없습니다.그리고 은행 링크가 성공적인 지불 요청을 반환하고 있으며, 그렇게 되면 많은 서비스를 요청하고 많은 데이터를 처리해야 합니다.이 작업은 10초 이상 걸릴 수 있지만 뱅크링크는 시간 초과 기간이 정해져 있습니다.그래서 나는 은행 링크를 인정하고 그에게 나가는 길을 알려주고, 그가 이미 떠났을 때 내 일을 합니다.
초기 요청을 처리하는 스크립트가 처리 대기열에 항목을 만든 다음 즉시 반환하도록 합니다.그런 다음 대기열에 대기 중인 모든 작업을 정기적으로 실행하는 별도의 프로세스(via cron)를 생성합니다.
당신에게 필요한 것은 이런 종류의 설정입니다.
"http 포크"를 자신이나 다른 스크립트에 사용할 수 있습니다.제 말은 이런 것입니다.
// parent sript, called by user request from browser
// create socket for calling child script
$socketToChild = fsockopen("localhost", 80);
// HTTP-packet building; header first
$msgToChild = "POST /sript.php?¶m=value&<more params> HTTP/1.0\n";
$msgToChild .= "Host: localhost\n";
$postData = "Any data for child as POST-query";
$msgToChild .= "Content-Length: ".strlen($postData)."\n\n";
// header done, glue with data
$msgToChild .= $postData;
// send packet no oneself www-server - new process will be created to handle our query
fwrite($socketToChild, $msgToChild);
// wait and read answer from child
$data = fread($socketToChild, $dataSize);
// close connection to child
fclose($socketToChild);
...
이제 하위 스크립트:
// parse HTTP-query somewhere and somehow before this point
// "disable partial output" or
// "enable buffering" to give out all at once later
ob_start();
// "say hello" to client (parent script in this case) disconnection
// before child ends - we need not care about it
ignore_user_abort(1);
// we will work forever
set_time_limit(0);
// we need to say something to parent to stop its waiting
// it could be something useful like client ID or just "OK"
...
echo $reply;
// push buffer to parent
ob_flush();
// parent gets our answer and disconnects
// but we can work "in background" :)
...
주요 아이디어는 다음과 같습니다.
- 사용자 요청에 의해 호출된 상위 스크립트;
- 부모가 동일한 서버(또는 다른 서버)에 있는 자식 스크립트(부모 또는 다른 스크립트와 동일)를 호출하고 요청 데이터를 제공합니다.
- 부모님은 사용자에게 OK라고 말하고 끝납니다.
- 아동 노동
자녀와 상호 작용해야 하는 경우 - "통신 매체"로 DB를 사용할 수 있습니다. 부모는 자녀 상태를 읽고 명령을 작성할 수 있으며 자녀는 명령을 읽고 상태를 작성할 수 있습니다.여러 하위 스크립트에 대해 필요한 경우 사용자 측에서 하위 ID를 유지하여 각 하위 스크립트의 상태를 확인할 때마다 해당 ID를 부모에게 보내야 합니다.
저는 여기서 그것을 찾았습니다 - http://linuxportal.ru/forums/index.php/t/22951/
파일 서버의 스크립트가 명령줄에서 트리거된 것처럼 실행되도록 호출하는 것은 어떻습니까?PHP의 exec을 사용하여 이 작업을 수행할 수 있습니다.
스크립트가 브라우저와의 대화를 완료한 후에 무언가를 실행하는 PHP 함수 register-shutdown-function을 사용할 수 있습니다.
ignore_user_abort도 참조하십시오. 그러나 register_shutdown_function을 사용하는 경우에는 이 함수가 필요하지 않습니다.같은 페이지에서,set_time_limit(0)
스크립트 시간 초과를 방지합니다.
대기열, exec 또는 cron을 사용하면 이 간단한 작업에 오버킬이 됩니다.동일한 스크립트 내에 머물러 있지 않을 이유가 없습니다.이 조합은 저에게 매우 효과적이었습니다.
ignore_user_abort(true);
$response = "some response";
header("Connection: close");
header("Content-Length: " . mb_strlen($response));
echo $response;
flush(); // releasing the browser from waiting
// continue the script with the slow processing here...
자세한 내용은 PHP에서 Ajax 요청에 응답한 후 프로세스를 계속하는 방법을 참조하십시오.
매우 짧은 시간 동안 cURL을 사용할 수 있습니다.기본 파일은 다음과 같습니다.
<?php>
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "http://example.com/processor.php");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_TIMEOUT_MS, 10); //just some very short timeout
curl_exec($ch);
curl_close($ch);
?>
다음은 프로세서 파일입니다.
<?php
ignore_user_abort(true); //very important!
for($x = 0; $x < 10; $x++) //do some very time-consuming task
sleep(10);
?>
보다시피 짧은 시간(이 경우 10밀리초) 후에 상위 스크립트가 시간 초과됩니다.이 .CURLOPT_TIMEOUT_MS
이렇게 작동하지 않을 것입니다, 이 경우, 그것은 다음과 같습니다.curl_setopt($ch, CURLOPT_TIMEOUT, 1)
.
따라서 프로세서 파일에 액세스하면 사용자(즉, 호출 파일)가 연결을 중단하더라도 프로세서 파일은 해당 작업을 수행합니다.
물론 GET 또는 POST 매개 변수를 페이지 간에 전달할 수도 있습니다.
서버와 서버 간에 http 요청을 작성할 수 있습니다.(브라우저가 필요하지 않음).백그라운드 http 요청을 만드는 비밀은 매우 작은 시간 제한을 설정하는 것이므로 응답은 무시됩니다.
이 기능은 해당 번데기에 사용한 기능입니다.
MAY 31 PHP 비동기 배경 요청 PHP에서 비동기 요청을 만드는 다른 방법(배경 모드 시뮬레이션).
/**
* Another way to make asyncronous (o como se escriba asincrono!) request with php
* Con esto se puede simpular un fork en PHP.. nada que envidarle a javita ni C++
* Esta vez usando fsockopen
* @author PHPepe
* @param unknown_type $url
* @param unknown_type $params
*/
function phpepe_async($url, $params = array()) {
$post_params = array();
foreach ($params as $key => &$val) {
if (is_array($val)) $val = implode(',', $val);
$post_params[] = $key.'='.urlencode($val);
}
$post_string = implode('&', $post_params);
$parts=parse_url($url);
$fp = fsockopen($parts['host'],
isset($parts['port'])?$parts['port']:80,
$errno, $errstr, 30);
$out = "POST ".$parts['path']." HTTP/1.1\r\n";
$out.= "Host: ".$parts['host']."\r\n";
$out.= "Content-Type: application/x-www-form-urlencoded\r\n";
$out.= "Content-Length: ".strlen($post_string)."\r\n";
$out.= "Connection: Close\r\n\r\n";
if (isset($post_string)) $out.= $post_string;
fwrite($fp, $out);
fclose($fp);
}
// Usage:
phpepe_async("http://192.168.1.110/pepe/feng_scripts/phprequest/fork2.php");
자세한 내용은 http://www.phpepe.com/2011/05/php-asynchronous-background-request.html 을 참조하십시오.
이 함수들을 세 개의 스크립트로 나눌 수 있습니다. 1.프로세스를 시작하고 실행자를 통해 두 번째 프로세스를 호출합니다.command
이것은 또한 http call을 통해 실행될 수 있습니다. 2. 두 번째 것은 데이터베이스 처리를 실행할 것이고 마지막 것은 마지막 것 3. 마지막 것은 이메일을 보낼 것입니다.
아, 제가 당신의 요구 사항을 잘못 이해했습니다.실제로는 다음과 같습니다.
- 스크립트가 사용자가 제어하지 않는 외부 소스로부터 입력을 수신함
- 스크립트는 입력을 처리하고 검증하며 외부 앱이 정상인지 여부를 알려주고 세션을 종료합니다.
- 스크립트는 장기간 실행되는 성공을 시작합니다.
이 경우 외부 작업 대기열 및/또는 cron을 사용하면 됩니다.입력의 유효성을 검사한 후 작업 상세 내역을 대기열에 삽입하고 종료합니다.그런 다음 다른 스크립트를 실행하고 대기열에서 작업 세부 정보를 선택한 다음 더 긴 프로세스를 시작할 수 있습니다.알렉스 호완스키의 생각이 옳습니다.
미안해요, 처음에 살짝 스친 건 인정해요.
저는 사용자와 프로세스를 계속하는 것보다 마지막에 새로운 비동기 요청을 생성하는 것을 추천합니다.
당신은 여기서 대답을 사용하여 다른 요청을 생성할 수 있습니다: 비동기 PHP 호출?
Apache에서php.ini
config 파일, 출력 버퍼링이 비활성화되었는지 확인합니다.
output_buffering = off
언급URL : https://stackoverflow.com/questions/3833013/continue-php-execution-after-sending-http-response
'programing' 카테고리의 다른 글
aspx 페이지 뒤에 있는 코드의 변수를 호출하는 방법 (0) | 2023.07.30 |
---|---|
Node.js가 지원하는 인코딩 목록 (0) | 2023.07.30 |
utf8_bin vs. utf_bin_ci (0) | 2023.07.30 |
내 사이트에서 실제로 history.js를 어떻게 사용합니까? (0) | 2023.07.30 |
#1148 - 사용된 명령은 이 MariaDB 버전에서 허용되지 않습니다. (0) | 2023.07.30 |