Kører en PHP app på windows - daemon eller cron?

Indlæg af Hanne Mølgaard Plasc

Problem



Jeg har brug for nogle implementeringsråd. Jeg har en MYSQL DB, der vil blive skrevet til fjernt for opgaver at behandle lokalt, og jeg har brug for min ansøgning, som er skrevet i PHP for at udføre disse opgaver imediatly, som de kommer ind.


Men selvfølgelig må min PHP app fortælle hvornår man skal køre. Jeg tænkte på at bruge cron jobs, men min app er på en Windows-maskine. For det andet skal jeg konstant kontrollere hvert par sekunder, og cron kan kun gøre hvert minut.


Jeg tænkte på at skrive en PHP-daemon, men jeg forstår hvordan det går på arbejde, og hvis det er en god idé!


Jeg vil sætte pris på noget råd om den bedste måde at gøre dette på.

Bedste reference


pyCron er et godt CRON-alternativ til Windows: [6]


pyCron


Da denne opgave er ret simpel, ville jeg bare oprette pyCron for at køre følgende script hvert minut:


set\_time\_limit(60); // one minute, same as CRON ;)
ignore\_user\_abort(false); // you might wanna set this to true

while (true)
{
    $jobs = getPendingJobs();

    if ((is\_array($jobs) === true) && (count($jobs) > 0))
    {
        foreach ($jobs as $job)
        {
            if (executeJob($job) === true)
            {
                markCompleted($job);
            }
        }
    }

    sleep(1); // avoid eating unnecessary CPU cycles
}


På denne måde, hvis computeren går ned, har du en worst case-forsinkelse på 60 sekunder.


Du vil måske også undersøge semaforer eller en slags låsestrategi som at bruge en APC-variabel eller kontrollere, om der findes en låsningsfil for at undgå løbevilkår, f.eks. Ved hjælp af APC:


set\_time\_limit(60); // one minute, same as CRON ;)
ignore\_user\_abort(false); // you might wanna set this to true

if (apc\_exists('lock') === false) // not locked
{
    apc\_add('lock', true, 60); // lock with a ttl of 60 secs, same as set\_time\_limit

    while (true)
    {
        $jobs = getPendingJobs();

        if ((is\_array($jobs) === true) && (count($jobs) > 0))
        {
            foreach ($jobs as $job)
            {
                if (executeJob($job) === true)
                {
                    markCompleted($job);
                }
            }
        }

        sleep(1); // avoid eating unnecessary CPU cycles
    }
}





Hvis du holder dig til PHP-dæmonen, gør dig selv en tjeneste og slip den idé, brug Gearman i stedet.


REDIGER : Jeg spurgte et beslægtet spørgsmål en gang, der kunne interessere dig: Anatomi af et distribueret system i PHP.

Andre referencer 1


Jeg vil foreslå noget ud over det sædvanlige: Du sagde, du skal køre opgaven, når dataene er skrevet til MySQL. Det betyder, at MySQL 'ved', at noget skal udføres.
Det lyder som et perfekt scenario for MySQLs UDF sys\_exec. [8]


I grund og grund ville det være rart, hvis MySQL kunne påberåbe sig et eksternt program, når der var sket noget.
Hvis du bruger den nævnte UDF, kan du udføre et php script indefra - lad os sige, INSERT eller UPDATE trigger.
På den anden side kan du gøre det mere ressourcevenligt og skabe MySQL Event (forudsat at du bruger en passende version), der ville bruge sys\_exec til at påberåbe et PHP script, der gør visse opdateringer med foruddefinerede intervaller - der reducerer behovet for Cron eller ethvert lignende program, der kan udføre noget med foruddefinerede intervaller.

Andre referencer 2


Jeg ville bestemt ikke anbefale at bruge cronjobs til dette.


cronjobs er en god ting og meget nyttig og nem til mange formål, men som du beskriver dine behov tror jeg, at de kan producere flere komplikationer, end de gør godt. her er nogle ting at overveje:



  • Hvad sker der, hvis job overlapper hinanden? man tager længere tid at udføre end et minut? er der nogen delte ressourcer/deadlocks/tempfiles? - Den mest almindelige metode er at bruge en låsfil og stoppe udførelsen, hvis den er optaget rigtigt ved starten af ​​programmet. men programmet skal også kigge efter yderligere job lige inden det afsluttes. - Dette kan dog også blive kompliceret på Windows-maskiner, fordi de ikke understøtter skrive låse ud af kassen

  • cronjobs er en smerte i ræven for at opretholde. hvis du vil overvåge dem, skal du implementere yderligere logik som en check, når programmet løb sidste gang. dette kan dog blive svært, hvis dit program kun skal køre på forespørgsel. Den bedste måde ville være en slags 'jobudfyldt' felt i databasen eller slette rækker, der er blevet behandlet.

  • På de fleste unix-baserede systemer er cronjobs ret stabile nu, men der er mange situatinos hvor du kan bryde dit cronjob system. de fleste af dem er baseret på menneskelig fejl. for eksempel kan en sysadmin, der ikke forlader crontab-editoren korrekt i redigeringstilstanden, forårsage, at alle cronjobs slettes. mange virksomheder har heller ikke et ordentligt overvågningssystem af de ovenfor anførte grunde og bemærker, så snart deres tjenester har problemer. på dette tidspunkt har ingen ofte skrevet ned/sat under versionskontrol, hvilke cronjobs skal løbe, og wild gætte og genopbygningsarbejde begynder.

  • cronjob maintaince kan være yderligere kompliceret, når eksterne værktøjer bruges, og miljøet ikke er et native unix-system. sysadmins er nødt til at få kendskab til flere programmer, og de kan have potentielle fejl.



Jeg tror ærligt, at bare et lille script, som du starter fra konsollen, og lad åbne er helt fint.


<?php
while(true) {
 $job = fetch\_from\_db();
 if(!$job) { 
    sleep(10) 
 } else {
    $job->process();
 }
}


Du kan også røre en fil (ændre ændringstidsstempel) i hvert loop, og du kan skrive et nagioscript, der kontrollerer, at tidsstempel bliver forældet, så du ved, at dit job stadig kører ...


hvis du vil have det til at starte med systemet, anbefaler jeg en deamon.


ps: I firmaet jeg arbejder er der meget af baggrundsaktivitet for vores hjemmeside (gennemsøgning, opdateringsprocesser, beregninger mv.) og cronjobs var et rigtigt rod, da jeg startede der. deres var spredt over forskellige servere med ansvar for forskellige opgaver. Databaser blev adgang til vildt over internettet. et ton af nfs filesytems, samba aktier osv. var på plads for at dele resouces. stedet var fuld af enkelte punkter i fejl, flaskehalse og noget konstant brød. der var så mange teknologier involveret, at det var meget svært at vedligeholde, og når noget ikke fungerede, havde det brug for timer med at spore problemet og en anden time af hvad den del selv skulle gøre.


Nu har vi et samlet opdateringsprogram, der er ansvarligt for bogstaveligt talt, det kører på flere servere, og de har en config-fil, der definerer de jobs, der skal køres. eveyrthing bliver afsendt fra en forældreproces, der gør en uendelig sløjfe. det er nemt at overvåge, customice, synkronisere og alt går glat. det er overflødigt, det er synkroniseret og granulariteten er fint. så det kører parallelt og vi kan skala op til så mange servere som vi kan lide.


Jeg foreslår virkelig at sætte mig ned for tid nok og tænke over alt som helhed og få et billede af det komplette system. derefter investere tid og kræfter for at gennemføre en løsning, der vil fungere fint i fremtiden, og spredes ikke tonsvis af forskellige programmer i hele dit system.


pps:


Jeg læste meget om minimumsintervallet på 1/5 minutter for cronjobs/opgaver. du kan nemt arbejde rundt det med et vilkårlig script, der tager over det interval:


// run every 5 minutes = 300 secs
// desired interval: 30 secs
$runs = 300/30; // be aware that the parent interval needs to be a multiple of the desired interval
for($i=0;$i<$runs;$i++) {
 $start = time();
 system('myscript.php');
 sleep(300/10-time()+$start); // compensate the time that the script needed to run. be aware that you have to implement some logic to deal with cases where the script takes longer to run than your interavl - technique and problem described above
}

Andre referencer 3


Dette ligner et job for en jobserver;) Kig på Gearman. Den ekstra fordel ved denne tilgang er, at dette udløses af fjernsiden, når og kun da er der noget at gøre, i stedet for afstemning. Specielt i intervaller mindre end (lad os sige) 5 min. Afstemning er ikke særlig effektiv mere afhængigt af de opgaver, som jobbet udfører. [9]

Andre referencer 4


Den hurtige og beskidte måde er at skabe en loop, der løbende kontrollerer om der er nyt arbejde.


Psuedo-kode


set\_ini("max\_execution\_time", "3600000000"); 
$keeplooping = true;
while($keeplooping){

   if(check\_for\_work()){
      process\_work();
   }
   else{
     sleep(5);
   }

   // some way to change $keeplooping to false
   // you don't want to just kill the process, because it might still be doing something
}

Andre referencer 5


Har du prøvet windows scheduler (leveres med Windows som standard)? I dette skal du give php-sti og din php-filsti. Det virker godt

Andre referencer 6


Kan du ikke skrive et java/c ++-program, der vil forespørge efter dig gennem et indstillet tidsinterval? Du kan få dette inkluderet i listen over opstartsprogrammer, så det løber altid også. Når en opgave er fundet, kan den klare det på en separat tråd selv og behandle flere anmodninger og markere andre færdige.

Andre referencer 7


Den mest enkle måde er at bruge integrere Windows-tidsplan.


Kør dit script med php-cli.exe med udfyldt php.ini med udvidelser, som dit script har brug for.


Men jeg bør sige at i praksis har du ikke brug for så kort tidsinterval for at køre dine planlagte job. Bare lav nogle tests for at få den bedste tidsintervalværdi for din ene. Det anbefales ikke at indstille tidsintervallet mindre end et minut .


Og en anden lille rådgiver: Lav en låsfil i begyndelsen af ​​dit script (php flock-funktionen), kontrollér for tilgængelighed at skrive ind i denne låsfil for at forhindre, at du arbejder med to eller flere kopier samme tid, og i slutningen af ​​scriptet afbrydes det efter oplåsning.


Hvis du skal skrive outputresultat til DB, skal du prøve at bruge MySQL TRIGGERS i stedet for PHP. Eller brug begivenheder i MySQL.