HTTP প্রতিক্রিয়া প্রেরণের পরে পিএইচপি প্রক্রিয়াকরণ চালিয়ে যান


103

আমার স্ক্রিপ্ট সার্ভার দ্বারা কল করা হয়। সার্ভার থেকে আমি গ্রহণ করব ID_OF_MESSAGEএবং TEXT_OF_MESSAGE

আমার স্ক্রিপ্টে আমি আগত পাঠ্যগুলি পরিচালনা করব এবং প্যারামগুলির সাথে প্রতিক্রিয়া উত্পন্ন করব: ANSWER_TO_IDএবং RESPONSE_MESSAGE

সমস্যাটি হ'ল আমি অযোগ্যকে প্রতিক্রিয়া পাঠাচ্ছি "ID_OF_MESSAGE", তবে সার্ভার যা আমাকে হ্যান্ডেল করতে বার্তা প্রেরণ করবে তার বার্তাটি আমার কাছে প্রেরণ করা হবে (এর অর্থ আমি তাকে এই আইডিতে প্রতিক্রিয়া প্রেরণ করতে পারি), http প্রতিক্রিয়া 200 পাওয়ার পরে।

সমাধানগুলির মধ্যে একটি হ'ল ডেটাবেজে বার্তা সংরক্ষণ এবং কিছু ক্রোন তৈরি করা যা প্রতি মিনিটে চলবে, তবে আমাকে তাত্ক্ষণিক প্রতিক্রিয়া বার্তা উত্পন্ন করতে হবে।

সার্ভারের HTTP প্রতিক্রিয়া 200 তে কীভাবে প্রেরণ করা যায় এবং পিএইচপি স্ক্রিপ্ট চালানো চালিয়ে যাওয়া ছাড়াও এর কোনও সমাধান আছে?

আপনাকে অনেক ধন্যবাদ

উত্তর:


195

হ্যাঁ. তুমি এটি করতে পারো:

ignore_user_abort(true);
set_time_limit(0);

ob_start();
// do initial processing here
echo $response; // send the response
header('Connection: close');
header('Content-Length: '.ob_get_length());
ob_end_flush();
ob_flush();
flush();

// now the request is sent to the browser, but the script is still running
// so, you can continue...

5
কী এটি কি জীবন্ত সংযোগের মাধ্যমে করা সম্ভব?
Congelli501

4
দুর্দান্ত !! এই প্রশ্নের একমাত্র প্রতিক্রিয়া যা আসলে কাজ করে !!! 10 পি +
মার্টিন_ল্যাক্স

4
দুর্দান্ত উত্তর! আমি বদলেছি একমাত্র জিনিস set_time_limit(0);। আপনি সম্ভবত এটি ডিফল্ট 30 সেকেন্ডের চেয়ে বেশি সময়ের জন্য চালিত করতে চান, তবে এটি যদি অসীম লুপে যায় তবে অনির্দিষ্টকালের জন্য সমস্যা তৈরি করতে পারে! আমার php.iniফাইলে আমার একটি দীর্ঘ মান সেট আছে ।
সিজে ডেনিস

9
দয়া করে নোট করুন যে কোনও বিষয়বস্তু-এনকোডিং শিরোনাম যদি 'কিছুই নয়' ব্যতীত অন্য কোনও কিছুতে সেট করা থাকে তবে এটি এই উদাহরণটিকে অকেজো হিসাবে উপস্থাপন করতে পারে কারণ এটি ব্যবহারকারীকে পুরো সম্পাদনার সময় (সময়সীমা অবধি?) অপেক্ষা করতে দেয়। সুতরাং একে একে নিশ্চিত হয়ে ওঠুন এটি স্থানীয় পরিবেশের পরিবেশে কাজ করবে এবং 'কনটেন্ট-এনকোডিং' শিরোনামটিকে 'কোনওটিই নয়' সেট করুন:header("Content-Encoding: none")
ব্রায়ান

18
টিপ: আমি পিএইচপি-এফপিএম ব্যবহার শুরু করেছি, তাই fastcgi_finish_request()শেষে আমাকে যুক্ত করতে হয়েছিল
ভিসিপিটেল্লি

47

আমি এখানে প্রচুর প্রতিক্রিয়া দেখেছি যা ব্যবহারের পরামর্শ দেয় ignore_user_abort(true);তবে এই কোডটি প্রয়োজনীয় নয়। এর ফলে আপনার স্ক্রিপ্টটি নিশ্চিত হয়ে যায় যে ব্যবহারকারী অবতরণ করা ইভেন্টটিতে প্রতিক্রিয়া প্রেরণের আগেই তার স্ক্রিপ্টটি কার্যকর করা অব্যাহত রেখেছে (তাদের ব্রাউজারটি বন্ধ করে দিয়ে বা অনুরোধটি থামাতে পালাতে চাপ দিয়ে)। তবে আপনি যা চাইছেন তা নয় not আপনি প্রতিক্রিয়া প্রেরণের পরে মৃত্যুদন্ড কার্যকর করতে বলছেন। আপনার যা দরকার তা হ'ল নিম্নলিখিত:

    // Buffer all upcoming output...
    ob_start();

    // Send your response.
    echo "Here be response";

    // Get the size of the output.
    $size = ob_get_length();

    // Disable compression (in case content length is compressed).
    header("Content-Encoding: none");

    // Set the content length of the response.
    header("Content-Length: {$size}");

    // Close the connection.
    header("Connection: close");

    // Flush all output.
    ob_end_flush();
    ob_flush();
    flush();

    // Close current session (if it exists).
    if(session_id()) session_write_close();

    // Start your background work here.
    ...

যদি আপনি উদ্বিগ্ন হন যে আপনার ব্যাকগ্রাউন্ডের কাজ পিএইচপি-র ডিফল্ট স্ক্রিপ্ট প্রয়োগের সময়সীমাটির চেয়ে বেশি সময় নেয়, তবে set_time_limit(0);শীর্ষে থাকুন।


4
প্রচুর বিভিন্ন সংমিশ্রণের চেষ্টা করেছেন, এটিই কাজ করে !!! ধন্যবাদ কোস্টা কনটোস !!!
মার্টিন_লাইক্স

4
অ্যাপাচি 2, পিএইচপি 7.0.32 এবং উবুন্টু 16.04 এ পুরোপুরি কাজ করে! ধন্যবাদ!
কাইলবাঙ্গা

4
আমি অন্যান্য সমাধান চেষ্টা করেছি, এবং কেবলমাত্র এটিই আমার পক্ষে কাজ করেছিল। লাইন ক্রম পাশাপাশি গুরুত্বপূর্ণ।
সিনিসা

34

আপনি যদি ফাস্টসিজিআই প্রসেসিং বা পিএইচপি-এফপিএম ব্যবহার করেন তবে আপনি এটি করতে পারেন:

session_write_close(); //close the session
ignore_user_abort(true); //Prevent echo, print, and flush from killing the script
fastcgi_finish_request(); //this returns 200 to the user, and processing continues

// do desired processing ...
$expensiveCalulation = 1+1;
error_log($expensiveCalculation);

সূত্র: https://www.php.net/manual/en/function.fastcgi-finish-request.php

পিএইচপি ইস্যু # 68722: https://bugs.php.net/bug.php?id=68772


4
এর জন্য ধন্যবাদ, কয়েক ঘন্টা ব্যয় করার পরে এটি আমার জন্য এনজিএক্সে কাজ করেছে
এহসান

ধন্যবাদ ডার্কইউরন! পিএইচপি-এফএমপি ব্যবহার করে আমাদের জন্য দুর্দান্ত উত্তর, কেবল আমার সমস্যার সমাধান!
সিনিসা

21

আমি এই ইস্যুতে কয়েক ঘন্টা ব্যয় করেছি এবং আমি এই ফাংশনটি নিয়ে এসেছি যা অ্যাপাচি এবং এনগিনেক্সে কাজ করে:

/**
 * respondOK.
 */
protected function respondOK()
{
    // check if fastcgi_finish_request is callable
    if (is_callable('fastcgi_finish_request')) {
        /*
         * This works in Nginx but the next approach not
         */
        session_write_close();
        fastcgi_finish_request();

        return;
    }

    ignore_user_abort(true);

    ob_start();
    $serverProtocole = filter_input(INPUT_SERVER, 'SERVER_PROTOCOL', FILTER_SANITIZE_STRING);
    header($serverProtocole.' 200 OK');
    header('Content-Encoding: none');
    header('Content-Length: '.ob_get_length());
    header('Connection: close');

    ob_end_flush();
    ob_flush();
    flush();
}

আপনার দীর্ঘ প্রক্রিয়াজাতকরণের আগে আপনি এই ফাংশনটি কল করতে পারেন।


4
এই রক্তাক্ত সুন্দর! উপরের সবকিছুর চেষ্টা করার পরেও এই একমাত্র জিনিস যা এনজিএনএক্সের সাথে কাজ করে।
মশলা

আপনার কোডটি এখানে কোডের মতো প্রায় একই তবে আপনার পোস্টটি পুরানো :) +1
অ্যাকাউন্টেন্ট

filter_inputফাংশন দিয়ে সাবধান থাকুন এটি কখনও কখনও NULL ফেরত দেয়। বিশদ জন্য এই ব্যবহারকারীর অবদান দেখুন
অ্যাকাউন্টেন্ট

4

@Vcampitelli দ্বারা উত্তরটি কিছুটা পরিবর্তন করেছেন। আপনার closeশিরোনামের দরকার নেই বলে মনে করবেন না । আমি ক্রোমে সদৃশ নিকটস্থ শিরোনামগুলি দেখছিলাম।

<?php

ignore_user_abort(true);

ob_start();
echo '{}';
header($_SERVER["SERVER_PROTOCOL"] . " 202 Accepted");
header("Status: 202 Accepted");
header("Content-Type: application/json");
header('Content-Length: '.ob_get_length());
ob_end_flush();
ob_flush();
flush();

sleep(10);

4
আমি মূল উত্তরে এটি উল্লেখ করেছি, তবে আমি এটি এখানেও বলব। আপনার অবশ্যই সংযোগটি বন্ধ করার দরকার নেই, তবে তারপরে যা ঘটবে তা হ'ল একই সংযোগের জন্য অনুরোধ করা পরবর্তী সম্পদ অপেক্ষা করতে বাধ্য হবে। সুতরাং আপনি এইচটিএমএল দ্রুত সরবরাহ করতে পারেন তবে আপনার জেএস বা সিএসএস ফাইলগুলির মধ্যে একটি ধীরে ধীরে লোড হতে পারে, কারণ সংযোগটি পরবর্তী সম্পদ পাওয়ার আগেই পিএইচপি থেকে প্রতিক্রিয়া পাওয়া শেষ করতে পারে। সুতরাং সেই কারণে সংযোগটি বন্ধ করা একটি ভাল ধারণা তাই ব্রাউজারটি এটি মুক্ত হওয়ার জন্য অপেক্ষা করতে হবে না।
নাট ল্যাম্পটন

3

আমি এটির জন্য পিএইচপি ফাংশন ব্যবহার করি

void register_shutdown_function ( callable $callback [, mixed $parameter [, mixed $... ]] )

http://php.net/manual/en/function.register-shutdown-function.php

সম্পাদনা করুন : উপরেরটি কাজ করছে না। দেখে মনে হচ্ছে কিছু পুরানো ডকুমেন্টেশন দিয়ে আমাকে বিভ্রান্ত করা হয়েছিল। পিএইচপি ৪.১ লিঙ্ক লিঙ্কের পরে নিবন্ধক_শটাউন_ফাংশনের আচরণটি পরিবর্তিত হয়েছে


এটি যা চাওয়া হচ্ছে তা নয় - এই ফাংশনটি মূলত স্ক্রিপ্ট সমাপ্তির ইভেন্টটিকে প্রসারিত করে এবং এখনও আউটপুট বাফারের অংশ।
ফিজ্ক

4
এটি একটি upvote মূল্য হিসাবে পাওয়া যায়, কারণ এটি কাজ করে না তা দেখায়।
ট্রেন্ডফিশার

4
ডিট্টো - আপোটিভ করা কারণ আমি এটিকে উত্তর হিসাবে দেখার আশা করছিলাম এবং এটি কার্যকর হয় না তা দেখার জন্য দরকারী।
হ্যাপিডোগ

3

আমি পাইথ্রেড ইনস্টল করতে পারি না এবং পূর্ববর্তী সমাধানগুলিও আমার পক্ষে কাজ করে না। আমি কাজের জন্য কেবল নিম্নলিখিত সমাধান পেয়েছি (রেফ: https://stackoverflow.com/a/14469376/1315873 ):

<?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');
?>

2

আমার কাছে এমন কিছু আছে যা সংকুচিত করতে পারে এবং প্রতিক্রিয়া পাঠাতে পারে এবং অন্যান্য পিএইচপি কোডটি কার্যকর করতে দেয়।

function sendResponse($response){
    $contentencoding = 'none';
    if(ob_get_contents()){
        ob_end_clean();
        if(ob_get_contents()){
            ob_clean();
        }
    }
    header('Connection: close');
    header("cache-control: must-revalidate");
    header('Vary: Accept-Encoding');
    header('content-type: application/json; charset=utf-8');
    ob_start();
    if(phpversion()>='4.0.4pl1' && extension_loaded('zlib') && GZIP_ENABLED==1 && !empty($_SERVER["HTTP_ACCEPT_ENCODING"]) && (strpos($_SERVER["HTTP_ACCEPT_ENCODING"], 'gzip') !== false) && (strstr($GLOBALS['useragent'],'compatible') || strstr($GLOBALS['useragent'],'Gecko'))){
        $contentencoding = 'gzip';
        ob_start('ob_gzhandler');
    }
    header('Content-Encoding: '.$contentencoding);
    if (!empty($_GET['callback'])){
        echo $_GET['callback'].'('.$response.')';
    } else {
        echo $response;
    }
    if($contentencoding == 'gzip') {
        if(ob_get_contents()){
            ob_end_flush(); // Flush the output from ob_gzhandler
        }
    }
    header('Content-Length: '.ob_get_length());
    // flush all output
    if (ob_get_contents()){
        ob_end_flush(); // Flush the outer ob_start()
        if(ob_get_contents()){
            ob_flush();
        }
        flush();
    }
    if (session_id()) session_write_close();
}

1

পিএইচপি ফাইল_জেট_কন্টেন্টস ব্যবহারের ক্ষেত্রে, সংযোগটি যথেষ্ট নয়। পিএইচপি এখনও সার্ভারের মাধ্যমে eof জাদুকরী প্রেরণের জন্য অপেক্ষা।

আমার সমাধানটি 'সামগ্রী-দৈর্ঘ্য:' পড়তে হবে

এখানে নমুনা:

প্রতিক্রিয়া.এফপি:

 <?php

ignore_user_abort(true);
set_time_limit(500);

ob_start();
echo 'ok'."\n";
header('Connection: close');
header('Content-Length: '.ob_get_length());
ob_end_flush();
ob_flush();
flush();
sleep(30);

বন্ধ রেখার প্রতিক্রিয়াতে "\ n" নোট করুন, অপেক্ষা করার আগে যদি ফাগেটটি না পড়ে থাকে।

read.php:

<?php
$vars = array(
    'hello' => 'world'
);
$content = http_build_query($vars);

fwrite($fp, "POST /response.php HTTP/1.1\r\n");
fwrite($fp, "Content-Type: application/x-www-form-urlencoded\r\n");
fwrite($fp, "Content-Length: " . strlen($content) . "\r\n");
fwrite($fp, "Connection: close\r\n");
fwrite($fp, "\r\n");

fwrite($fp, $content);

$iSize = null;
$bHeaderEnd = false;
$sResponse = '';
do {
    $sTmp = fgets($fp, 1024);
    $iPos = strpos($sTmp, 'Content-Length: ');
    if ($iPos !== false) {
        $iSize = (int) substr($sTmp, strlen('Content-Length: '));
    }
    if ($bHeaderEnd) {
        $sResponse.= $sTmp;
    }
    if (strlen(trim($sTmp)) == 0) {
        $bHeaderEnd = true;
    }
} while (!feof($fp) && (is_null($iSize) || !is_null($iSize) && strlen($sResponse) < $iSize));
$result = trim($sResponse);

আপনি এই স্ক্রিপ্টটি দেখতে পাচ্ছেন যে যদি সামগ্রীর দৈর্ঘ্য পৌঁছে যায় তবে এটি সম্পর্কে অপেক্ষা করুন।

আশা করি এটি সাহায্য করবে


1

এই নিবন্ধগুলি উদ্ধৃত করে আমি এপ্রিল ২০১২ এ রাসমাস লেয়ার্ডর্ফকে এই প্রশ্নটি জিজ্ঞাসা করেছি:

আমি প্ল্যাটফর্মটি অবহিত করার জন্য একটি নতুন পিএইচপি অন্তর্নির্মিত ফাংশনটি বিকাশের পরামর্শ দিয়েছি যাতে কোনও আউটপুট (স্টাডাউট?) উত্পন্ন হবে না (যেমন কোনও ফাংশন সংযোগ বন্ধ করার ক্ষেত্রে যত্ন নিতে পারে)। রাসমাস লেয়ারডর্ফ এর প্রতিক্রিয়া জানিয়েছিলেন:

গিয়ারম্যান দেখুন । আপনি সত্যই চান না যে আপনার সম্মুখভাগের ওয়েব সার্ভারগুলি এভাবে ব্যাকএন্ড প্রসেসিং করছে।

আমি তার পয়েন্টটি দেখতে পারি এবং কিছু অ্যাপ্লিকেশন / লোডিং দৃশ্যের জন্য তার মতামতকে সমর্থন করি! যাইহোক, অন্য কয়েকটি পরিস্থিতিতে, ভিসিপিটেলি এট আল এর সমাধানগুলি ভাল।


0

আপনি যদি প্রতিক্রিয়া শিরোনামগুলির সাথে কোনও ছলনা করতে চান না তবে এটির অন্য পদ্ধতির এবং এর উপযুক্ত বিবেচনা রয়েছে। আপনি যদি অন্য কোনও প্রক্রিয়াতে থ্রেড শুরু করেন তবে ডাকা ফাংশনটি তার প্রতিক্রিয়ার জন্য অপেক্ষা করবে না এবং একটি চূড়ান্ত এইচটিপি কোড সহ ব্রাউজারে ফিরে আসবে। আপনাকে পাইথ্রেড কনফিগার করতে হবে ।

class continue_processing_thread extends Thread 
{
     public function __construct($param1) 
     {
         $this->param1 = $param1
     }

     public function run() 
     {
        //Do your long running process here
     }
}

//This is your function called via an HTTP GET/POST etc
function rest_endpoint()
{
  //do whatever stuff needed by the response.

  //Create and start your thread. 
  //rest_endpoint wont wait for this to complete.
  $continue_processing = new continue_processing_thread($some_value);
  $continue_processing->start();

  echo json_encode($response)
}

একবার আমরা কার্যকর করি $ চালিয়ে যাওয়া_প্রসেসিং- > শুরু () শুরু করুন ( পিএইচপি ) এই থ্রেডের রিটার্নের ফলাফলের জন্য অপেক্ষা করবে না এবং তাই যতক্ষণ পর্যন্ত বিশ্রাম_পয়েন্টটি বিবেচনা করা হয়। হয়ে গেছে।

Pthreads সাহায্যে কিছু লিঙ্ক

শুভকামনা।


-1

আমি জানি এটি একটি পুরানো, তবে সম্ভবত এই সময়ে দরকারী।

এই উত্তর দিয়ে আমি আসল প্রশ্নটি সমর্থন করি না তবে কীভাবে এই সমস্যাটি সঠিকভাবে সমাধান করা যায়। আশা করি এটি অন্যান্য মানুষকে এই জাতীয় সমস্যা সমাধানে সহায়তা করবে।

আমি র‌্যাবিট এমকিউ বা অনুরূপ পরিষেবাগুলি ব্যবহার করার এবং কর্মীর উদাহরণগুলি ব্যবহার করে ব্যাকগ্রাউন্ড ওয়ার্কলোড চালানোর পরামর্শ দেব । পিএইচপি জন্য amqplib নামে একটি প্যাকেজ রয়েছে যা আপনার জন্য RabbitMQ ব্যবহারের সমস্ত কাজ করে।

প্রো এর:

  1. এটি উচ্চ অভিনয়
  2. পুরোপুরি কাঠামোগত এবং রক্ষণাবেক্ষণযোগ্য
  3. এটি কর্মীদের উদাহরণগুলির সাথে নিখুঁতভাবে স্কেলেবল

নেগস:

  1. RabbitMQ অবশ্যই সার্ভারে ইনস্টল করা উচিত, এটি কিছু ওয়েব হোস্টারে সমস্যা হতে পারে।
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.