Przetwarzanie dużych ilości danych w PHP bez limitu czasu przeglądarki

Mam tablicę numerów telefonów, Około 50,000. Próbuję przetwarzać i wysyłać masowe wiadomości SMS na te numery za pomocą interfejsu API innych firm, ale przeglądarka zatrzyma się na kilka minut. Szukam lepszej opcji.

Przetwarzanie danych obejmuje sprawdzenie typu numeru telefonu komórkowego (np. CDMA), przypisanie unikalnych identyfikatorów do wszystkich numerów w celu dalszego odniesienia, sprawdzenie unikalnych opłat sieciowych / krajowych itp.

Myślałem o kolejkowaniu danych w bazie danych i użyciu crona do wysyłania o 5K przez partię co minutę, ale to zajmie trochę czasu, jeśli jest wiele wiadomości. Jakie mam inne opcje?

Używam Codeigniter 2 na serwerze XAMPP.

Author: Charles, 2011-04-04

4 answers

Napisałbym dwa skrypty:

Plik index.php:

<iframe src="job.php" frameborder="0" scrolling="no" width="1" height="1"></iframe>
<script type="text/javascript">
    function progress(percent){
        document.getElementById('done').innerHTML=percent+'%';
    }
</script><div id="done">0%</div>

Plik job.php:

set_time_limit(0);                   // ignore php timeout
ignore_user_abort(true);             // keep on going even if user pulls the plug*
while(ob_get_level())ob_end_clean(); // remove output buffers
ob_implicit_flush(true);             // output stuff directly
// * This absolutely depends on whether you want the user to stop the process
//   or not. For example: You might create a stop button in index.php like so:
//     <a href="javascript:window.frames[0].location='';">Stop!</a>
//     <a href="javascript:window.frames[0].location='job.php';">Start</a>
// But of course, you will need that line of code commented out for this feature to work.

function progress($percent){
    echo '<script type="text/javascript">parent.progress('.$percent.');</script>';
}

$total=count($mobiles);
echo '<!DOCTYPE html><html><head></head><body>'; // webkit hotfix
foreach($mobiles as $i=>$mobile){
    // send sms
    progress($i/$total*100);
}
progress(100);
echo '</body></html>'; // webkit hotfix
 36
Author: Christian,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-04-04 08:23:48

Zakładam, że te liczby są w bazie danych, jeśli tak, powinieneś dodać nową kolumnę zatytułowaną isSent(lub cokolwiek chcesz).

Następny akapit, który wpisałeś, powinien być ustawiony w kolejce i ewentualnie zrobić noc/tydzień / w razie potrzeby. O ile nie masz konkretnego powodu, nie powinno się tego robić luzem na żądanie. Możesz nawet dodać kolumnę do db, aby zobaczyć, kiedy została ostatnio sprawdzona, więc jeśli liczba nie została sprawdzona przez co najmniej X dni, możesz wykonać sprawdzenie tej liczby na żądanie.

Przetwarzanie danych obejmuje sprawdzenie typu numeru telefonu komórkowego (np. CDMA), przypisanie unikalnych identyfikatorów do wszystkich numerów w celu dalszego odniesienia, sprawdzenie unikalnych opłat sieciowych / krajowych itp.

Ale to wciąż prowadzi do tego samego pytania, jak to zrobić dla 50 000 liczb na raz. Skoro wspomniałeś o zadaniach cron, zakładam, że masz dostęp SSH do serwera, co oznacza, że nie potrzebujesz przeglądarki. Te zadania cron mogą być wykonywane za pomocą wiersza poleceń jako takie:

/usr / bin /php / home/username/example.com/myscript.php

Moim zaleceniem jest przetwarzanie 1000 liczb na raz co 10 minut przez cron i czas, jak długo to trwa, a następnie zapisanie go do DB. Ponieważ używasz Zadania cron, nie wydaje się, aby były to wiadomości SMS wrażliwe na czas, więc można je rozłożyć. Gdy już wiesz, jak długo trwało uruchamianie tego skryptu 50 razy (50*1000 = 50k), możesz zaktualizować swoje zadanie cron, aby działało więcej / mniej często.

$time_start = microtime(true);
set_time_limit(0);

function doSendSMS($phoneNum, $msg, $blah);

$time_end = microtime(true);
$time = $time_end - $time_start;
saveTimeRequiredToSendMessagesInDB($time);

Możesz również zauważyć set_time_limit( 0), to powie PHP, aby nie timeout po domyślnych 30 sekundach. Jeśli jesteś w stanie zmodyfikować PHP.plik ini wtedy nie musisz wpisywać tej linii kodu. Nawet jeśli jesteś w stanie edytować PHP.plik ini, nadal polecam nie zmieniać tej funkcji, ponieważ możesz chcieć, aby inne strony przestały działać.

Http://php.net/manual/en/function.set-time-limit.php

 1
Author: user2150628,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-04-04 00:36:58

Jeśli nie jest to sytuacja Jednorazowa, rozważ inżynierię lepszym rozwiązaniem.

To, co w zasadzie chcesz, to kolejka, do której proces związany z przeglądarką może pisać, a niż 1-N procesów roboczych może odczytywać i aktualizować.

Umieszczenie pracy w kolejce powinno być raczej niedrogie - być może kilka prostych poleceń INSERT do SQL RDBMS.

Wtedy możesz mieć demona lub dwa (lub 100, rozproszonych na wielu serwerach), które odczytują z kolejki i procesu rzeczy. Będziesz chciał być ostrożny i uniknąć dwóch pracowników podejmujących się tego samego zadania, ale nie jest to trudne do zakodowania.

Więc twój przepływ pracy związany z przeglądarką to: kliknij jakiś przycisk, który powoduje dodanie kilku rzeczy do kolejki, a następnie przekierowanie do interfejsu "status kolejki", gdzie użytkownik może obserwować, jak system przeżuwa całą swoją pracę.

Taki system jest fajny, bo łatwo go skalować poziomo.

EDIT: odpowiedź Christiana Sciberrasa to idąc w tym kierunku, z tym, że przeglądarka prowadzi obie strony (dodaje do kolejki, a następnie uruchamia proces roboczy)

 1
Author: timdev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-04-04 03:39:11

Cronjob byłby najlepszym rozwiązaniem, nie rozumiem, dlaczego zajęłoby to dłużej niż robienie tego w przeglądarce, jeśli jedynym problemem w tej chwili jest wyłączanie czasu przeglądarki.

Jeśli nalegasz na robienie tego przez przeglądarkę, innym rozwiązaniem byłoby robienie tego w partiach powiedzmy 1000 i przekierowanie do tego samego skryptu, ale z pewnym odniesieniem do miejsca, w którym ostatnio pojawił się w zmiennej $_GET.

 0
Author: John Mellor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-04-04 01:43:20