PHP 500 internal error, a háttérben mégis fut a PHP

PHP 500 internal error, a háttérben mégis fut a PHP
2020-12-12T16:48:48+01:00
2020-12-15T17:27:27+01:00
2022-10-15T21:26:11+02:00
Gabor.Buczko
Sziasztok!

Készítettem egy PHP kódot, ami egy tömb minden elemével lefuttat egy API hívást.
Egy LOG fájlba lefűzöm a kezdési időt, minden hivás végén elvégzett művelet sorszámát+aktuális futási időt és a teljes futási időt a végén.
A max_exceution_time 1800 mp.
PHP verzió 7.4.

Elindítom a php fájlt, beírja a LOG fájlba a kezdési időt és szépen sorban, ahogy futtatja az API hívásokat, fűzi hozzá az ID-t és az aktuális futási időt a kezdéstől.

Nagyjából 90 mp után kiírja a böngésző, hogy 500 Internal Server Error.
Ettől függetlenül, ha a LOG txt fájl frissítem, látszik, hogy csinálni és LOG-olja az API kéréseket. 2135 elem van a tömbben, mind a 2135-re elindítja az API hívást és helyes választ is ad vissza. Az utolsó elemnél az aktuális futási idő 623 mp.

Egy valamit nem fűz hozzá, az a teljes futási idő.

Láttatok már hasonlót?
Ez valami PHP beállítási hiba lehet?

Köszönöm előre is a segítséget!
Mutasd a teljes hozzászólást!
Valószínű Fast-CGI vagy FPM módban fut a PHP, és a webszerver nem várja meg a szkript futását, Fast-CGI I/O timeout-al vagy hasonlóval elszáll. Ezt a webszerver naplóban tudod megnézni. Ilyen hosszú feladatot NEM futtatunk webszerveren keresztül, csak CLI-ből! Továbbá, ez üzemeltetési kérdés (bár kétségtelen hogy hibás programozói gyakorlat eredménye).
Mutasd a teljes hozzászólást!

  • Nem kliens oldalon szeretném futtatni, hanem CRON-ból adott időközönként lekérdezni és adatbázisban frissíteni az elemeket.
    Csak tesztelni szerettem volna, hogy teszi-e a dolgát.
    Mutasd a teljes hozzászólást!
  • Nem tudom, hogy mi okozza a jelenséget (ezért kicsit OFF), de ha már ilyet tesztelsz, akkor CLI-ben tedd (gondolom a CRON sem wget-eleni fog). Pl. simán lehet, hogy más php konfig van az egész alatt ez esetben, arról nem is beszélve, hogy a http szerver sincs a képben ezen az úton...
    Mutasd a teljes hozzászólást!
  • Az, hogy CRON vagy nem CRON az jelen esetben teljesen mindegy, a hangsúly nem ezen van. Az a lényeg hogy a hívás átmegy-e a webszerveren (HTTP-s megoldás) vagy nem, és utóbbi esetben (helyesen) command line-ból (CLI) történik. Ha helyesen utóbbit szeretnéd akkor úgy is kell tesztelni, t.i. teljesen más konfiguráció kell / lehet / illik a PHP alá az egyes üzemmódokban. Pl. a timeout CLI esetén alapban nagyon magas szokott lenni, vagy végtelen. A memória limitet is magasra lehet ott tenni, míg egy "sima" HTTP-s, webszerveren átmenő kérés ne fusson sokáig, és pláne ne egye meg az erőforrásokat. Tesztelni pontosan hogy a végleges módszerrel kell, hiszen ott kell majd jól működnie. Mi több, CLI-s szkriptet nem is szabad / illik semmilyen módon futtathatóvá tenni HTTP-n át. Ez is tervezési hiba, ha ilyet egyáltalán enged a kód.
    Mutasd a teljes hozzászólást!
  • TTP-s, webszerveren átmenő kérés ne fusson sokáig, és pláne ne egye meg az erőforrásokat


    Mert hogy ha  a kódod cli-ben futtatod ugyanazon a szerveren, akkor az kevésbé eszi az erőforrásokat?
    Attól hogy valamit elindítasz egy webszerveren, még nem biztos hogy meg akarod várni a végét. Hadd fusson a háttérben, majd egyszer végez és megkapod az eredményt.

    A cli-ben meg időzíteni tudod, hogy mikor végezze el, amit szeretnél. Meg lehet csinálni hogy felveszed a kérések közé, de akkor a CLI-nek állandóan futnia kell és ellenőriznie hogy a kérések között van-e új. Ha van, akkor elvégzi és utána? Akkor azzal ott külön meg kell küzdeni hogy felvegye a kapcsolatot velem, hogy végzett. Nem egyszerűbb ha elindítod a kérést a háttérben és majd jön a válasz?
    Mutasd a teljes hozzászólást!
  • Mert hogy ha  a kódod cli-ben futtatod ugyanazon a szerveren, akkor az kevésbé eszi az erőforrásokat?

    A hangsúly azon van, hogy ne a webszervert terhelje, ne annak egy szálát fogja, és ne annak a PHP konfigurációját próbálja meg használni. Főleg akkor amikor ilyen eset van, hogy timeout-ol. Továbbá, miért kellene egy háttérfolyamatot kitenni publikus URL-re? Ne már!!!

    Attól hogy valamit elindítasz egy webszerveren, még nem biztos hogy meg akarod várni a végét.

    Csakhogy NEM a webszerver processzen át akarom futtatni, hanem közvetlenül az értelmezőn át. Hatékonyabb, erre van kitalálva, és más a PHP konfiguráció is.

    Hadd fusson a háttérben, majd egyszer végez és megkapod az eredményt.

    Csakhogy mint láthatod nem kapod meg az eredményt mert időtúllépés történik, amiatt lesz 500-as HTTP error. Ezeknek NEM kell átmenniük a webszerver processzen! Ahogy írod, a nevében is benne van: HÁTTÉRfolyamat. Nem a fronton fut, hanem hátul.

    A cli-ben meg időzíteni tudod, hogy mikor végezze el, amit szeretnél.

    Ne keverd a CLI-t a CRON-al. Időzítésre utóbbi való.

    Meg lehet csinálni hogy felveszed a kérések közé, de akkor a CLI-nek állandóan futnia kell és ellenőriznie hogy a kérések között van-e új. Ha van, akkor elvégzi és utána? Akkor azzal ott külön meg kell küzdeni hogy felvegye a kapcsolatot velem, hogy végzett.

    Mi van? Ki beszélt itt ilyenről? miért kellene bárminek is folyamatosan futnia? Egy adott feladat időzített futtatásáról beszélünk úgy, hogy ne legyen hibaüzenet. Miért van a hibaüzenet? Mert teljesen feleslegesen átmegy egy webszerveren. NEM KELL ÍGY LENNIE.

    Nem egyszerűbb ha elindítod a kérést a háttérben és majd jön a válasz?

    De NEM jön válasz ha timeout-ol a frontban lévő webszerver (mint jelen esetben). Kikerülöd a lényeget: a CLI az CLI. Az Apache modul / fast-CGI / FPM más tészta. Más környezet, más paraméterek, más processz és más PHP.ini, a kettő NEM összekeverendő.

    Légyszives nekem ne akard megmagyarázni hogy ez hogyan működik.
    Mutasd a teljes hozzászólást!
  • Persze hogy háttér folyamat a webszerveren minden a háttérben fut, csak a végeredményt látod. Ahogy Gabor írta, ez egy API: 

    Készítettem egy PHP kódot, ami egy tömb minden elemével lefuttat egy API hívás

    Nekem viszont elmagyarázhatnád, hogy Te hogyan hívod meg távolról a CLI scriptet, ha nem használhatod hozzá a webszervert. Nála vannak az adatok, hogyan adja át?
    Mutasd a teljes hozzászólást!
  • Hali!

    Nekem viszont elmagyarázhatnád, hogy Te hogyan hívod meg távolról a CLI scriptet, ha nem használhatod hozzá a webszervert. Nála vannak az adatok, hogyan adja át?

    Lehet, hogy félreértettem valamit, de hol/miben látod azt, hogy távolról el szeretné érni azt a PHP-szkriptet (ami szkript „egy tömb minden elemével lefuttat egy API hívást”)? Úgy tűnik, hogy a kérdező készített egy szkriptet, ami egy külső (gondolom, távoli szerveren lévő – persze, ez nem feltétel) API-t ér el bizonyos adatokkal (ezek vannak a tömbben) és ezt a szkriptet időzítve, rendszeresen futtatná (mint ahogy' írja is). Nekem ez egyáltalán nem böngészőből, webszerveren keresztüli elérhetőséget jelent.

    Mutasd a teljes hozzászólást!
  • A témanyitó második hozzászólása:

    Nem kliens oldalon szeretném futtatni, hanem CRON-ból adott időközönként lekérdezni és adatbázisban frissíteni az elemeket.

    A lényeg: a webszervert ki kell hagyni a képből a háttérfolyamatoknál. Szerintem.
    Mutasd a teljes hozzászólást!
  • Írasd ki a hibákat.
    Ha pl. XML fájlokat vársz API hívásoknál, és feldolgoznád SimpleXML -el.
    Akkor könnyen 500 -as hibára futhat, ha nem valid XML -t kapsz vissza.
    Mutasd a teljes hozzászólást!
  • A CRON által elkldött emailben benne van az összes API által updatelt sor és a teljes futási idő is.
    Szóval lefut az egész annak ellenére, hogy nem jelzi ki, ha böngészőben futtatom.

    De valószínűleg megoldom úgy, hogy azonos szerveren fognak futni és sima SQL parancsokkal updateli az adott rekordokat API helyett. (Csak eddig azt mondták, hogy ez nem lehetséges. Így a futási idő nem lesz probléma.)
    Mutasd a teljes hozzászólást!
  • Az is tud ilyet okozni, ha túl nagy a fejléc. Például használsz egy firephp-t és túl nagy adatot írsz bele. Ez ráadásul függhet a szerver beállításoktól is, de ne kérdezd hogy hol kell állítani, csak én is jártam már így.
    Mutasd a teljes hozzászólást!
  • Szerintem teljesen felesleges találgatni, az 500-as hibakód elég általános. Az első hozzászólásomban írtam ezt: "Ezt a webszerver naplóban tudod megnézni." Ennyit kellene tenni, ott le lesz írva miért dobta ezt a hibakódot. Ez informatika, nem kitalálósdi. Szerintem.
    Mutasd a teljes hozzászólást!
  • Gondolod hogy én anno nem néztem a logot? Mivel többször le lett írva hogy tovább fut a script valószínűleg neki sem fogja írni, mivel nincs hiba.
    Mutasd a teljes hozzászólást!
  • Mivel többször le lett írva hogy tovább fut a script valószínűleg neki sem fogja írni, mivel nincs hiba.

    Nézd. Nem tudjuk mi van abban a szkriptben. Itt valaki XML-t emleget, te túl nagy fejléceket. Mire alapozod? Találgatsz. Ahogy én is. De mi a legvalószínűbb a témanyitó kérdése alapján? Mindössze annyi hogy sokáig fut a háttérben a szkript anélkül hogy választ adna, és a frontend webszerver eldobja közben a kapcsolatot. Mindez arra utal hogy a PHP Fast-CGI vagy FPM módban fut a háttérben, és a Fast-CGI I/O timeout egy normál érték (30-60 másodperc).

    A témanyitó azóta sem reagált semmiben érdemben, nem írta meg milyen módban fut a PHP, nem írta azt sem hogy mi van a webszerver naplóban. A többi már csak körítés, és a jó irányba terelő út: háttérfolyamatot NEM szuszakolunk át webszerveren. Pont.
    Mutasd a teljes hozzászólást!
  • A találgatással kapcsolatban egyetértek, de már elmondtátok hogy nézze meg a logot, stb. Innetől kezdve a találgatás marad

    Viszont a "timeout"-nak nem az lenne az értelme, hogy lekapcsolja magát? Mert mi értelme annak, hogy a beragadt scriptek azért futnak tovább, csak nem látjuk? És így akkor hogy hozol létre mondjuk egy long pollingot?
    Mutasd a teljes hozzászólást!
  • mi értelme annak, hogy a beragadt scriptek azért futnak tovább, csak nem látjuk?

    A script nem "ragadt" be, csak sokáig tart neki elvégezni a dolgát.

    És így akkor hogy hozol létre mondjuk egy long pollingot?

    Ez attól függ, hogy az adott helyzetben mi számít kliensnek.
    Ebben a topicban én úgy értelmezem a dolgot, hogy a topicnyitó php scriptje egy másik szerverre "kérdez be", tehát ez esetben ő a kliens. Ezt a "bekérdező" scriptet (akár valami polling-jellegű periodikusan ismételt művelet, akár nem) semmiképpen sem http szerveren keresztüli kérés "hatására" kell elindítani... egész egyszerűen azért, mert sokáig tart.
    Szerintem DJ_Tacee értékelése kb. ennyi (a kapott információk alapján sokkal több nem is lehetne), csak valami miatt nem értitek egymást...
    Mutasd a teljes hozzászólást!
  • Viszont a "timeout"-nak nem az lenne az értelme, hogy lekapcsolja magát?

    Csakhogy nem csak egy timeout van. A példa kedvéért, Fast-CGI esetén:

    FcgidBusyTimeout
    FcgidIdleTimeout
    FcgidIOTimeout
    FcgidConnectTimeout
    FcgidProcessLifeTime
    FcgidTimeScore

    Simán előállhat egy olyan helyzet hogy a frontend már eldobta a kapcsolatot (értsd: a webszerver a CGI között), de a CGI-s szkript fut tovább (egy másik timeout eléréséig). PHP esetén az is előállhat hogy addig fut ténylegesen míg a végére nem ér.
    Mutasd a teljes hozzászólást!
  • A PHP Fast-CGI módban fut.
    A webszerver logban nem jelenik meg semmi.

    Menet közben kihagytuk az API-s elérést (helyette adatbázis művelettel frissítettük a tartalmat), mert sikerült a cél szerverre feltenni és futtatni a PHP kódot CRON-ból. Így a futási idő 2-3 mp lett.
    Egyébként a php fájl, amit lefuttattam, alap esetben nem elérhető böngészőből, csak az adatok kiírása volt a cél és a tesztelés (természetesen user + password URL paraméterrel együttessel, hogy véletlenül se tudja bárki is lefuttatni).

    Amikor kész természetesen bekerül/t egy olyan mappába, ami nem public és csak CRON-ból futtatjuk. A kérdése arra irányult, hogy miért lehet ez a hiba, ha később előfordul, akkor tudjuk, hogy erre kell figyelni.

    Köszönöm a válaszokat!
    Mutasd a teljes hozzászólást!
Tetszett amit olvastál? Szeretnél a jövőben is értesülni a hasonló érdekességekről?
abcd