Autor Zpráva
mckay
Profil
Půjde o trochu složitější dotaz, nechci ho však dělit do více vláken, takže se pokusím o co nejvýstižnější popis + úvahy na toto téma.

Prostředí: Mám k dispozici linuxový server, na kterém nemám root oprávnění, ale většinu operací dělat můžu. Je na něm php, které budu spoustět příkazem v terminálu nad mým skriptem. Skript by měl být schopen běžet nekonečně dlouhou dobu, docíleno toho bude stylem while (true) Run(); . Reálně však vím, že se server každé pondělí v 0600 restartuje a proto budu mít zařízené, že se potom skript i znovu spustí (automatizovaným externím ssh připojením a nahozením skriptu znovu, CRON na tomto serveru k dispozici bohužel nemám).

Prohledal jsem diskusi vztahující se k tomuto tématu a narazil na vlákno z roku 2012, kde se mezi Alphardem a Keeehim rozhořela krátká diskuse na téma, zda php je na tento typ práce postavené, nebo ne. Závěr není úplně jednoznačný, ze zběžného progooglení jsem také zahlédl spíše dohady a empirické zkušenosti, ale staršího data.

1. Jaká je situace teď a jaké jsou Vaše empirické zkušenosti nyní?

Pomocí tohoto skriptu chci v určitých intervalech spouštět další php skripty, které mohou být i dlouhodobějšího charakteru. Procrawlování celého webu, vytažení subjektivně zajímavých informací, statistické zpracování dat dotažených z konkrétních zdrojů, upozornění emailem apod. Co tedy chci je, aby skript při každé iteraci cyklem podmíněně vypálil další proces (spuštění dalšího php skriptu), který provede svou práci a nějakým způsobem dá volajícímu skriptu vědět, že práci dokončit (s nějakým výstupem / exit kódem / návratovou hodnotou). Z hlediska jazyka k tomuto pravděpodobně použiji exec() nebo system() funkci. Jak ale dám od spouštěného skriptu vědět skriptu, ze kterého byl spuštěn, že byla práce dokončena.

Příklad scénáře:
1. Projíždím cyklem poprvé a startuji další skripty: skript1.php skript2.php + uspávám hlavní skript na 5 sekund,
2. skript2.php se stihne dokončit (a dá vědět, že se dokončil - Otázka 2: Jak dá vědět, že se dokončil?), skript1.php se nestihne dokončit a nijak vědět nedá,
3. Cyklus iteruje podruhé a ví, že skript2.php se dokončil a tedy ho pouští znovu. Ví, že skript1.php stále pracuje a tedy ho znovu nepouští a usíná na 5 sekund,
4. skript1.php a skript2.php se dokončují a dávají vědět, že jsou dokončeny
5. Cyklus iteruje potřetí a ví, že má pustit oba skripty znova... což taky udělá a zase spí.

A takhle dokola.

Jsem otevřen i více technickým řešením a workaroundům, kdy pokud neexistuje v jazyce mechanismus na výše popsaný scénář, bude možné tuto funkcionalitu naprogramovat (např. nějakým rozumným způsobem zapisováním do souboru o stavu operace a kontrolou těchto souborů při každé iteraci).

Suma sumárum 2 otázky, těším se na Vaše odpovědi.

Edit: Napadla mě v souvislosti s tímto ještě jedna věc - co se stane, pokud po naincludeování souboru do toho dlouho běžícího skriptu, includeovaný soubor smažu?
Keeehi
Profil
mckay:
Pokud vím, tak exec a system jsou synchronní. Takže čekají, než skončí program, který volali. Ten volaný program se dá spustit na pozadí, tím že se na konec přidá & ale v tom případě se s ním asi nedá dále komunikovat (kromě postraních kanálů, jako třeba přes soubory, fronty nebo databázi).
Podíval bych se na pcntl_fork a další funkce z rodiny pcntl_* které umožňují nakolonování procesu kde v jednom vlákně bude běžet ta řídící smyčka a v jiných si php spusí synchonní exec. Vlákna si mezi sebou umí posílat zprávy (v PHP jsem to nikdy nedělal) a nebo na sebe vyčkávat.
Celé je to pak velká sranda, když jeden proces čeká na druhý zatímco on čeká na ten první, nebo když více procesů přistupuje k stejnému prostředku (např. souboru) a jiné. Také se to perfektně debuguje, když chyba se projeví jen občas, protože se dva procesy zrovna náhodou potkají. No, užiješ si :)
Jan Tvrdík
Profil
mckay, Keeehi:
Asynchronní pouštění procesů se dělá přes proc_open.

mckay:
Proč to nechceš řešit normálně (tj. přes nějakou frontu)?

Vaše odpověď

Mohlo by se hodit


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm:

0