Kirjautuminen

Haku

Tehtävät

Keskustelu: Nettisivujen teko: Sivun suoritus 5 minuutin välein

Sivun loppuun

Juhku [02.11.2013 12:50:30]

#

Moi!

Onko esim. PHP mahdollisuus tehdä sellainen sivu, jota palvelin suorittaisi vaikka 5min välein automaattisesti?
Jos ei niin millä tavalla saisi suoritettua sellaisen?

Macro [02.11.2013 13:00:41]

#

Linux: http://en.wikipedia.org/wiki/Cron
Windows: http://en.wikipedia.org/wiki/Windows_Task_Scheduler

Metabolix [02.11.2013 13:31:06]

#

Yleensä helpoin ja yksinkertaisin ratkaisu on säilyttää jossain tietoa, milloin skripti on viimeksi suoritettu, ja hoitaa rästit aina tavanomaisen sivunlatauksen alussa.

Juhku [02.11.2013 21:27:38]

#

Ok, miten saisin phpn tunnistamaan MYSQLn avulla vaikka suorittamaan, jonkun jutun 5min välein?

Edit miten tuolla cronilla saa avattua .PHP tiedoston 5min välein?

gamehouse [03.11.2013 01:43:42]

#

Juhku kirjoitti:

Edit miten tuolla cronilla saa avattua .PHP tiedoston 5min välein?

Laittamalla crontabiin (ajat terminaalissa "crontab -e") tämän:

*/5 * * * * php5 /polku/tähän/foo.php

Olettaen että sinulla on PHP5

Juhku [03.11.2013 10:23:27]

#

Juu, kyllä palvelin on kaikissa ohjelmissa ajan tasalla, kiitos tästä. Tämä foorumi on kyllä ihan välttämätön apu kaikessa ohjelmoinnissa! :)

Metabolix [03.11.2013 10:52:15]

#

Harvoin kylläkään PHP-tulkin nimi on php5, vaan yleensä se on vain php. Lisäksi tuolla tavalla suoritus saattaa käyttää eri asetuksia kuin normaali suoritus sivunlatauksella, joten jos ilmenee ongelmia, voi olla helpompi vain tehdä sivunlataus:

*/5 * * * * wget -qO/dev/null http://sivusto/sivu.php

Tämä rivi taas vaatii, että palvelimella on wget.

t0ll0 [03.11.2013 11:46:42]

#

Sopiva aihe niin kysytäänpä tässä.
Aina ei ole cronia käytössä ja aikanaan mietin sql:n ja alla olevan väliltä kumpaa käyttäisin ja tähän päädyin.

$cron['tiedosto.php'] = 3600; // tiedosto avaimena ja arvoksi aika sekunteina, tunti
$cron['tiedosto2.php'] = 86400; // 24h

foreach($cron as $tiedosto => $aika){
  if((time() - filemtime($tiedosto)) > $aika){ // tiedoston muokkausaika on yli asetetun arvon
   include($tiedosto);
   touch($tiedosto); // vaihdetaan muokkausaika nykyiseen
  }
}

Itse pidän tästä siksi, ettei tarvitse parin tietueen takia sql-taulua luoda, mutta onko tässä jotain mitä en ole ottanut huomioon? Huomattavia suorituskyky eroja tai jotain ongelmakohtia vai voinko tulevaisuudessakin tuota tarvittaessa käyttää.

Sami [03.11.2013 12:25:14]

#

Riippuu siitä mitä haluat sen tekevän. Jos haluat että koodi suoritetaan seuraavan kerran vähintään tunti (tai päivä) edellisen suorituskerran jälkeen niin tuo toiminee lähes aina (talviaikaan siirryttäessä saattaa tulla pidempikin tauko ja kesäaikaan siirryttäessä lyhyempi, riippuen siitä kuinka time, filemtime ja touch käsittelevät nämä tilanteet).

Jos taas haluat että se suoritetaan esimerkiksi aina tasatunnein (kun ensimmäinen kävijä tulee sivulle tasatunnin jälkeen) niin sitten tuo ei toimi.

t0ll0 [03.11.2013 12:32:07]

#

Sami kirjoitti:

Riippuu siitä mitä haluat sen tekevän. Jos haluat että koodi suoritetaan seuraavan kerran vähintään tunti (tai päivä) edellisen suorituskerran jälkeen niin tuo toiminee lähes aina (talviaikaan siirryttäessä saattaa tulla pidempikin tauko ja kesäaikaan siirryttäessä lyhyempi, riippuen siitä kuinka time, filemtime ja touch käsittelevät nämä tilanteet).

Jos taas haluat että se suoritetaan esimerkiksi aina tasatunnein (kun ensimmäinen kävijä tulee sivulle tasatunnin jälkeen) niin sitten tuo ei toimi.

Jeps, mainitsemasi asiat olen jopa tajunnut ottaa huomioon :)
Eli tuon tarkoituksena on hoitaa aiemmin kuvatusti rästit sivulatauksen yhteydessä. Ei ole itselleni tullut sivustojen kanssa tilannetta, jossa jotain tarvitsisi tehdä myös silloin kun kukaan ei sivua käytä.

Metabolix [03.11.2013 12:56:27]

#

Toimiihan tuollainen idea myös näennäisesti tasatunnein suoritukseen, kun vähän muuttaa ehtoa:

if (floor(filemtime($tiedosto) / $aika) < floor(time() / $aika))

Joka tapauksessa tällaisessa ratkaisussa pitää huomioida, että koodin suoritus ei tapahdu äärettömän nopeasti, joten tarvitaan jonkinlainen lukitus, ettei päivitys pääse tapahtumaan kahta kertaa samaan aikaan. Turhan lukituksen välttämiseksi voi tarkistaa ehdon sekä ennen että jälkeen lukitsemisen.

if (ehto) {
	lukitse();
	if (ehto) {
		päivitä();
	}
	avaa();
}

Lukitusta käsitellään tässä koodivinkissä; lopussa on ihan tällainen esimerkkikin.

t0ll0 [03.11.2013 16:59:36]

#

Tosiaan, tuo tiedoston lukitus lienee hyvä asia vaikka useimmiten suoritettava tiedosto sisältää vain taulujen puhdistuksia tai muuta kevyttä hommaa. Eli ei haittaisi vaikka kerran kuussa ajettava tiedosto ajettaisiinkin kahdesti yhtäaikaisen sivulatauksen seurauksena.

Tein kuitenkin muutoksia tuohon koodinpätkään ja nyt näyttää tältä.

foreach($cron as $tiedosto => $aika){
 if((time() - filemtime($tiedosto)) > $aika){ // tiedoston muokkausaika on yli asetetun arvon

  $open_tiedosto = fopen($tiedosto,'r+');

  if(flock($open_tiedosto, LOCK_EX|LOCK_NB)){ // lukitaan tiedosto

   $ignore_vanha = ignore_user_abort(true);
   touch($tiedosto); // vaihdetaan muokkausaika nykyiseen
   include($tiedosto);
   flock($open_tiedosto, LOCK_UN); // lukitus pois
   fclose($open_tiedosto);
   ignore_user_abort($ignore_vanha);

  }
 }
}

Mikäli manuaalia oikein ymmärsin niin käyttämällä myös LOCK_NB:tä voin jättää toisen tarkistuksen tekemättä? Sen käyttöä tosin rajaa ympäristö, muttei se minulle ole ongelma. Ainakin tekemäni testit vaikuttasivat siltä, että oikein toimii. Mikäli siinä kuitenkin on jotain ongelmaa mitä en huomaa niin silloin täytynee laittaa toisen ehdon lisäksi myös clearstatcache koska filemtime-funktion tulos säilytetään välimuistissa.

Tämän koodin suoritusaika getrusage-funktion avulla tarkasteltuna on kuitenkin lähes kaksinkertainen aikaisempaan versioon verrattuna joten onko tämän käyttö tarpeellista riippuu ihan projektista ja suoritettavien tiedostojen suoritteista. Hifistelyä tämä millisekuntin osista välittäminen ;)

Metabolix [03.11.2013 21:09:06]

#

t0ll0 kirjoitti:

Mikäli manuaalia oikein ymmärsin niin käyttämällä myös LOCK_NB:tä voin jättää toisen tarkistuksen tekemättä?

Et voi noin päin. Onhan edelleen mahdollista, että rinnakkaiset suoritukset pääsevät samaan aikaan if-lauseen sisään ja sitten ensimmäinen ehtii hoitaa homman ja avata lukon niin nopeasti, että toinen onnistuu myös lukitsemaan. Toisin päin voisit tehdä: ensin lukitus, ja jos lukitus onnistuu, aletaan tutkia, mitä pitäisi ajaa.

Oikeastaan LOCK_NB:llä ei ole asiassa muuta merkitystä kuin se, että seuraavan lataajan ei tarvitse odottaa turhaan. Toisaalta tästä seuraa myös ongelmia: seuraava käyttäjä voi saada vanhentuneen sivun, koska päivitys on vielä kesken, tai pahimmillaan rikkinäisen sivun, kun päivitys on puolitiessä. Voi siis olla parempi, että kaikki joutuvat odottamaan päivityksen ajan.

Useimmilla kerroilla ei pidä ajaa mitään, ja lukitus näyttää vievän lähes kymmenkertaisesti aikaa tuohon filemtime-tarkistukseen nähden. Pitää siis tutkia ja punnita tapauskohtaisesti, mikä on nopeinta. Toisaalta ajankäyttö on niin mitätön, että jos sivustolla ei vieraile satoja kävijöitä joka sekunti, asialla ei luultavasti ole merkitystä.

t0ll0 [04.11.2013 01:09:26]

#

No juu, ajattelin tilannetta vain omalle kohdalleni.

Vielä omin sanoin miten ymmärrän tuon toiminnan. Ilman LOCK_NB:tä jonossa olevat käyttäjät odottavat tiedoston aukaisemista jonka jälkeen jokainen vuorollaan varaa tiedoston omaan käyttöönsä. Tässä tilanteessa siis lukituksen jälkeinen ehdon tarkistus on todellakin tärkeä. LOCK_NB:n kanssa jonoa ei tule vaan jos tiedosto on jo lukittuna niin jatketaan suoraa eteenpäin. Tämä siis jos useat käyttäjät edes kerkiävät ensimmäisen ehtolauseen sisään.

Itse käytän tuota sql-taulujen puhdisteluihin vanhoista tietueista kuukausi/vuosi-tasolla enkä siinä asiassa näe turhaa odottelua tarpeelliseksi. Toisaalta todennäköisyys jonon muodostumiseen näillä kävijämäärillä ei päätä huimaa joten kahden ehtolauseen käyttäminen ja LOCK_NB:stä luopuminen ei merkitse yhtään mitään. :)

Metabolix [04.11.2013 13:12:28]

#

Toisaalta jos on vain tarkoitus tyhjentää harvakseltaan tauluja, onko ylipäänsä järkeä tehdä tuollaista systeemiä? Voisi ajaa kyselyt joka kerta, satunnaisesti, vuoden välein cronilla tai jopa käsin (ts. erillisellä siivoussivulla, jolla itse joskus vierailee).

t0ll0 [04.11.2013 20:19:35]

#

Metabolix kirjoitti:

Toisaalta jos on vain tarkoitus tyhjentää harvakseltaan tauluja, onko ylipäänsä järkeä tehdä tuollaista systeemiä? Voisi ajaa kyselyt joka kerta, satunnaisesti, vuoden välein cronilla tai jopa käsin (ts. erillisellä siivoussivulla, jolla itse joskus vierailee).

Projektikohtaisesti.. Jos cronia ei ole käytettävissä niin mieluummin tuommoinen järjestelmä kuin itsensä sitouttaminen siivouksiin palkatta. Jokaisella sivulatauksella tehdyt kyselyt toki kävisivät tuommoiseen kevyeen hommaan myös.


Sivun alkuun

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta