Check alle échte Black Friday-deals Ook zo moe van nepaanbiedingen? Wij laten alleen échte deals zien

[PHP/Mysql] Cron Daemon

Pagina: 1
Acties:
  • 239 views sinds 30-01-2008

  • _Gekkie_
  • Registratie: Oktober 2000
  • Laatst online: 24-06 20:21

_Gekkie_

And the cow said: Helloooooow?

Topicstarter
Ik zit hier met een uitdaging: ik wil een database gestuurde cron-deamon bouwen. Ik vraag me alleen af óf dat verstandig is om zelf te bouwen óf dat het al bestaat (niet gevonden via google)

In het kort wil ik het volgende realiseren:
- er zijn meerdere triggers voor jobs
Er kunnen dus meerdere jobs tegelijk aan de deamon en onafhankelijk van elkaar worden ge-queued
- er moeten jobs ge-queued kunnen worden.
Doordat er meerdere jobs tegelijk zouden moeten kunnen draaien waarvan er één later een te queuen job in de weg zit moet het dus een soort wachtrij ondersteunen, de jobs moeten immers wel uitgevoerd worden
- jobs moeten naast elkaar uitgevoerd kunnen worden of expliciet opvolgend ivm afhankelijkheid
Er zouden jobs kunnen zijn die níet tegelijk mogen draaien ivm afhankelijkheden

Dat betekent dat er dus een aantal zaken zijn om rekening mee te houden:
- er moet één proces andere php processen op kunnen starten, monitoren en eventueel opvolgen
- taken kunnen bestaan uit het uitvoeren van een script op een bepaalde locatie of het uitvoeren van specifieke code
- een taak kan eenmalig of herhalend zijn
- de maximale looptijd van een taak kan eventueel overruled worden door een taak zelf (doordat deze de set_timeout() aanpast

Dit alles leidt tot een scheiding van functies die allen autonoom naast elkaar werken:
- een harvester
Dit is een proces wat de tabel `cronTab` uitleest en omzet naar `cronJob`
- een deaemon
Het voortuderend lopende proces die de `cronJob` tabel uitleest, verwerkt en eventueel processen start voor de verwerking van de jobs. Hier zit vrij weinig intelligentie in: de vertaalslag van definitie naar taak is al door de harvester uitgevoerd
- een worker
Deze spreekt eigenlijk voor zich. Dit zijn feitelijk de uitvoerende processen die door de daemon worden gestart. Deze voeren de code uit of `executen` de scripts zoals gedefinieerd in de `cronJob`.

Mijn vraag is eigenlijk: is dit wel verstandig? Doe ik er wel goed aan om een wiel (crontab) opnieuw uit te vinden?
grootste voordeel is denk ik dat dit vervolgens ook op windows / unix omgevingen hetzelfde werkt... ?
grootste nadeel is dat het wiel opnieuw uitvinden nu niet altijd het beste resultaat levert...

Any suggestions?

Gekkie is a proud member of TheBenny!


Verwijderd

Wat je zou kunnenn doen is via een 'gewone' cronjob een php file om de 30 seconden laten aanroepen. Vervolgens regel je in deze php file alle door jou gedefineerde cronjobs, die in de db staan opgeslagen.

Nadeel hiervan is dat je een marge van 30 seconde hebt op elke taak, maar dit lijkt me voor sommige dingen een prima oplossing.

  • _Gekkie_
  • Registratie: Oktober 2000
  • Laatst online: 24-06 20:21

_Gekkie_

And the cow said: Helloooooow?

Topicstarter
Dat is eigenlijk wat ik nu heb: 1 bestand die elke minuut wordt aangeroepen en vervolgens andere scripts eventueel include.. Daarbij een `lock` bijhoudt zodat scripts elkaar simpelweg nooit in de weg zitten... Probleem hiervan is is dat er dus eventueel processen zijn die elkaar in de weg gaan zitten...

voorbeeld:
10.00 - start script a. Dit zou bijvoorbeeld een backup script oid zijn, duurt 4 minuten om te draaien
10.01 - start script b. echter door de lock draait deze niet
10.04 - script a is klaar, maar script b heeft nooit gedraaid...

en de volgende dag dus weer hetzelfde...

los natuurlijk nog van het feit dat je nu nog steeds server gebonden bent voor de feitelijke te processen code... én dat je eventueel niet op exact hetzelfde moment twee scripts kunt draaien... (of juist twee keer hetzelfde script met andere omgevingsvariabelen... )

voorbeeld:
script a is een 'stuur mailing $id'
10.00 - start script a :
code:
1
2
3
$id=1;
include ('script a');
stuurMailing();

10.00 - start script a:
code:
1
2
3
$id=2;
include ('script a');
stuurMailing();


Dat kan dus eigenlijk niet... terwijl beide mailings wel gewoon om 10.00 los van elkaar verstuurd konden worden...

[ Voor 34% gewijzigd door _Gekkie_ op 13-08-2007 15:46 ]

Gekkie is a proud member of TheBenny!


Verwijderd

Misschien kan je een wat specifieker lock mechanisme maken?

Wat je eigenlijk wil is iets van losse threads maken/starten, maar ik weet eigenlijk niet eens of dit kan. Je kan wel java gebruiken binnen php, maar hier heb ik geen ervaring mee: http://www.php.net/manual/en/ref.java.php

Het lijkt me dat als in in 1 php beide aanroepen hebt staan, deze ook allebei (hetzij na elkaar) worden uitgevoerd?

  • _Gekkie_
  • Registratie: Oktober 2000
  • Laatst online: 24-06 20:21

_Gekkie_

And the cow said: Helloooooow?

Topicstarter
behalve dat variabelen en includes door elkaar heen gaan lopen ... :(

Vandaar de afzonderlijke workers: zo blijven alle variabelen apart en hebben ze geen last van elkaar. (op die wijze is het ook veel schaalbaarder naar meerdere machines, scripts e.d. die tegelijk uitvoeren)

Gekkie is a proud member of TheBenny!


Verwijderd

Dat je variabelen door elkaar gaan lopen ligt denk ik aan je implementatie.

Waarom vervang je dit:

code:
1
2
3
$id=1;
include ('script a');
stuurMailing();


Niet door dit:
code:
1
2
3
include_once('script a');
stuurMailing( 1 );
stuurMailing( 2 );


Uiteraard weet ik niet wat die stuurMailing precies doet, maar dit is maar een voorbeeld he :)

[ Voor 15% gewijzigd door Verwijderd op 13-08-2007 16:15 ]


  • _Gekkie_
  • Registratie: Oktober 2000
  • Laatst online: 24-06 20:21

_Gekkie_

And the cow said: Helloooooow?

Topicstarter
Verwijderd schreef op maandag 13 augustus 2007 @ 16:15:
Dat je variabelen door elkaar gaan lopen ligt denk ik aan je implementatie.

Waarom vervang je dit:

code:
1
2
3
$id=1;
include ('script a');
stuurMailing();


Niet door dit:
code:
1
2
3
include_once('script a');
stuurMailing( 1 );
stuurMailing( 2 );
Dit is gewoon een simpel voorbeeld. In weze is wat ik heb: meerdere hetzelfde genoemde klasses afhankelijk van bepaalde variabelen al dan niet worden geladen.. (dus wederom simpel gezegd:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
switch($x) {
    case '1':
        include('../1/lib/validator.php');
        $validator = new Validator();
        break;
    case '2':
        include('../2/lib/validator.php');
        $validator = new Validator();
        break;
    default:
        // dus eigenlijk zo:
        if (is_readable('../'.$x.'/lib/validator.php') {
            include('../'.$x.'/lib/validator.php');
        } else {
            include('/lib/validator.php');
        }
        $validator = new Validator();
}


wederom, dit is maar een simpel voorbeeld van 1 klasse, het is meer om duidelijk te maken dat je aan de hand van bepaalde variabelen binnen 1 applicatie op dezelfde plek hele andere dingen kunt doen / laden...

Gekkie is a proud member of TheBenny!


  • _Gekkie_
  • Registratie: Oktober 2000
  • Laatst online: 24-06 20:21

_Gekkie_

And the cow said: Helloooooow?

Topicstarter
Kleine update: dankzij classThread is het me nu gelukt om workerProcessen te starten. Nu moet het echter allemaal aan elkaar geknoopt worden... dat zal dus morgen wel gaan denk ik :)

Gekkie is a proud member of TheBenny!


  • FragFrog
  • Registratie: September 2001
  • Laatst online: 21:07
Met behulp van firedaemon kun je een PHP script als service draaien (aanroepen met "php.exe locatie/bestand.php"). Dan heb je geen last meer van de max_execute_time etc en hoef je dus ook niet om de 30 seconden een script aan te roepen.

Vervolgens kun je met sleep() en time() denk ik wel een aardig eind komen met schedulen - je laat je service een proces opstarten met het laagste que nummer in je database. Vervolgens wacht je tot die klaar is (exec() doet dit zelf al mooi voor je als je de output van je commando niet piped), kijk je hoe laat het is en als er nog tijd is voor een nieuwe ronde moet starten geef je opdracht tot het volgende item in de que.

Als je que dan klaar is voor een bepaalde tijdseenheid laat je'm simpelweg sleepen tot de volgende ronde, aan het einde van de sleep periode controleer je of't al tijd is, laat'm desnoods nog een minuutje slapen en begin je.

Dingen naast elkaar draaien zou -ook- kunnen door wel een output aan te geven in je exec call, je kan zelfs in je exec call PHP weer opnieuw aanroepen met een ander bestand als argument zodat ze naast elkaar draaien, maar dan heb je wel weer problemen met filelocks. Als je toch niet naar een bestand schrijft / leest geen probleem, anders zoals gezegd geen output pipen en lekker wachten tot't klaar is :)

[ Site ] [ twitch ] [ jijbuis ]


  • Flapp
  • Registratie: December 2004
  • Laatst online: 20-05-2024
als je shell toegang hebt kan je ook gewoon een cron daemon schrijven volgens de structuur die je voor een normale taal ervoor zou gebruiken.

en dan het scriptje via de CLI aanroepen.
dan kan je gewoon een while(true) of iets dergelijks gebruiken om een 'thread' te maken.
en dan gewoon bijvoorbeeld iedere keer een seconde laten wachten, en kijken of hij iets moet doen.

"Stilte, een gat in het geluid...."


  • _Gekkie_
  • Registratie: Oktober 2000
  • Laatst online: 24-06 20:21

_Gekkie_

And the cow said: Helloooooow?

Topicstarter
Ik heb shell access én cron access, dat is allemaal geen probleem. Ik wil alleen niet dat workers in elkaars userspace gaan zitten. Ze moeten echt strikt gescheiden blijven.

Dankzij 'classFork' heb ik nu een kleine test opzet gemaakt...
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
function getWork() {
 // de centrale functie het werk ophaalt / controleert of er nog wat te doen is?
}

class worker extends PHP_Fork {
    var $cronDefinition = '';
 
    function worker($name, $cronDefinition = false) {
        $this->PHP_Fork($name);
        if ($cronDefinition) $this->cronDefinition = $cronDefinition;
    }

    function run() {
        while (true) {
            $this->execute();
            $this->setAlive();
            sleep(1);
        }
    }

    function execute() {
      // doe hier het uitvoerende werk...
    }
}
class phpCronDaemon extends PHP_Fork {
    var $_sleepInt;
    var $_workers = array();
    var $_maxIdleTime;
    var $_respawnWorkers = array();

    function phpCronDaemon($name, &$workers, $maxIdleTime = 60, $interval = 60) {
        $this->PHP_Fork($name);
        $this->_sleepInt = $interval;
        $this->_workers = &$workers;
        $this->_maxIdleTime = $maxIdleTime;
        $this->_respawnWorkers = array();

        $this->setVariable('_workers', $this->_workers);
    }

    function run() {
        while (true) {
            $this->_detectDeadChilds();
            $this->_respawnDeadChilds();

            sleep($this->_sleepInt);
        }
    }

    function stopAllWorkers() {
        $this->_workers = $this->getWorkers();
        foreach($this->_workers as $worker) {
            $worker->stop();
            echo "Stopped " . $worker->getName() . "\n";
        }
        unset($this->_workers);
        $this->_workers = array();
        $this->setVariable('_workers', $this->_workers);
    }

    function getWorkers() {
        return $this->getVariable('_workers');
    }
   function _detectDeadChilds() {
        foreach ($this->_workers as $key => $worker) {
            if ($worker->getLastAlive() > $this->_maxIdleTime) {
                $threadName = $worker->getName();
                print time() . "-" . $this->getName() . "-" . $threadName . " seems to be finished...\n";
                $worker->stop();

                unset($worker);
                array_splice($this->_workers, $key, 1);
                $this->_respawnWorkers[] = $threadName;
                break;
            }
        }
    }

    function _respawnDeadChilds() {
        foreach ($this->_respawnWorkers as $key => $threadName) {
                $work = getWork();
                if (!empty($work)) {
                    $revivedWorker = &new worker ($threadName, $work);
                                if ($revivedWorker->_ipc_is_ok) {
                        $revivedWorker->start();
                        $this->_workers[] = &$revivedWorker;
                        print time() . "-" . $this->getName() . "- New instance of " . $threadName . " successfully spawned (PID=" . $revivedWorker->getPid() . ") starting work (". $work .")\n";
                        array_splice($this->_respawnWorkers, $key, 1);
                        $this->setVariable('_workers', $this->_workers);
                    } else {
                        print time() . "-" . $this->getName() . "-" . "Unable to create IPC segment...\n";
                    }
                }
        }
    }
}


Zo heb ik 1 process die afhankelijk van de functie getWork() eventueel een proces start en het werk laat uitvoeren... de functie getwork kan vervolgens de intelligentie krijgen om werk altijd aan te bieden en kan de phpCronDaemon zelf bepalen of werk tegelijk / los van elkaar moet gebeuren.

Maar nogmaals: is this the way to go?

Gekkie is a proud member of TheBenny!


  • _Gekkie_
  • Registratie: Oktober 2000
  • Laatst online: 24-06 20:21

_Gekkie_

And the cow said: Helloooooow?

Topicstarter
_kick_

Ik heb het project zoals ik het nu gemaakt heb alsvolgt online gezet: http://www.disney.com

Wie heeft er commentaar? :)

[ Voor 5% gewijzigd door Creepy op 13-10-2007 10:28 ]

Gekkie is a proud member of TheBenny!


  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 15:10

Creepy

Tactical Espionage Splatterer

Ho ff. Zo werkt het hier niet he ;)
Ik heb je URL weg gehaald want op deze manier is het gewoon spam.

Als je commentaar wilt op de code of opzet van de code dan zul je informatie moeten geven wat je hebt gedaan, waarom je dat hebt gedaan inclusief wat relevante code voorbeelden. Op deze manier kan er gepraat worden over het geheel. Een discussie over het programma, features, of het handig werkt voor de gebruiker etc. hoort hier niet thuis.

Als het je puur gaat om je product te laten zien dan hebben we daar een speciaal topic voor: [Alg] Welke tools heb jij gemaakt? - deel III.

[ Voor 15% gewijzigd door Creepy op 13-10-2007 10:31 ]

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney

Pagina: 1

Dit topic is gesloten.