Avatar billede nemlig Professor
23. april 2010 - 13:37 Der er 12 kommentarer og
1 løsning

Hvordan sikrer jeg, at samme script ikke køres på samme tid

Hejsa.

Jeg har et script, som hver dag sender en email. Scriptet kaldes af et cronjob, som kører mange gange i løbet af en dag.
Men scriptet skal kun køre 1 gang pr. dag.
Derfor har jeg lavet det sådan:

1. Tjek i MySQL, om scriptet er kørt i dag
2. Hvis ingen timestamp for dd. i MySQL, så kør scriptet ellers spring over.
3. Smid et timestamp i MySQL, hvis scriptet er kørt.

Men jeg har nu i nogle dage oplevet, at scriptet køres 2 gange på samme tid (samme sekund), og det lugter af, at cronjobbet kalder mit script dobbet, hvorfor scriptet når at køre begge gange inden der er skrevet til MySQL.

Kan man gøre et eller andet for at scriptet ikke køres dobbelt, hvis det skulle kaldes dobbelt?
Avatar billede DGudiksen Nybegynder
23. april 2010 - 15:39 #1
Hos din ydbyder burde du kunne sætte dit cronjob til kun at kører engang om dagen. f.eks hver dag klokken 16.00.

Den mulighed har jeg hvertfald hos min udbyder.
Avatar billede Slettet bruger
23. april 2010 - 15:47 #2
Hmm... Det eneste jeg lige kan finde på er, at lægge dags dato i et unikt (primary) felt, og så kun sende e-mailen hvis indsætningen af datoen lykkes.
Avatar billede nemlig Professor
23. april 2010 - 16:34 #3
DGudiksen: Ikke for at være uforskammet, men jeg søger ikke en løsning med frekvensen af cronjobbet :) Der er forskellige årsager til den måde cronjobbene afvikles (Drupal installation og nogle rettigheder).
Kimsey0: Det kan godt være, at jeg misforstår dit forslag, men er det ikke lige præcis det, jeg gør?
Avatar billede showsource Seniormester
23. april 2010 - 18:53 #4
Hvis det kører to gange på samme tid, så får du vel to datoer som er ens ?

Det burde kunne undgås hvis feltet er UNIQUE.
Og ellers er det vel noget med LOCK YABLES ?
http://dev.mysql.com/doc/refman/5.5/en/lock-tables.html
Avatar billede nemlig Professor
23. april 2010 - 23:09 #5
Showsource:
Jeg anvender UPDATE og ikke INSERT, når jeg indsætter date i databasen. Så er UNIQUE ligegyldigt.
Når jeg så tjekker, om scriptet er kørt tidligere, så tjekker jeg med:

$date = date("Y-m-d");
if($date != $row['cronjob_dato']) {   

Løsningen er måske LOCK TABLES.
Kan tabellerne også låses for at foretage forespørgsler - ellers kan jeg ikke se, at det hjælper.
Avatar billede nemlig Professor
24. april 2010 - 09:38 #6
Det med Lock Tables er lidt for avanceret for mig, og det ser også ud til, at det måske slet ikke er muligt på webhotellet.

Kunne løsningen være, at det første, jeg gør i scriptet, er at lave en UPDATE, hvor jeg fx sætter '1' i et tjek-felt, kører scriptet og til sidst ændrer tjek-feltet til '0'.

Altså dette forløb:

1. Kontroller, om scriptet er i gang ved at lave en forespørgsel på tjek-feltet.
2. Hvis ikke (hvor tjek-feltet = '0'), så sæt tjek-feltet til '1'
3. Kør scriptet
4. Smide dateoen i dato-feltet.
4. Ændre tjek-feltet til 0.

Denne løsning vil som det første opdatere MySQL, hvor min oprindelige løsning, først opdaterede MySQL, når hele scriptet var kørt via dato-feltet.

Når så scriptet kaldes millisekunder efter, kan det være, at det første kald har nået at sætte tjek-feltet til '1', hvorfor scriptet ikke køres 2. gang.

Jeg kan se, at der typisk går 0,3 til 0,6 sekund imellem dobbelt kaledene.
Avatar billede showsource Seniormester
24. april 2010 - 12:50 #7
Jeg er godt nok lettere forvirret.
Den eneste løsning jeg kan se, er at du deler dit cronjob op.
Altså to cronjobs

En foresp. kan evt. gå lynhurtigt, så ved næste er feltet atter 0 igen.
Avatar billede nemlig Professor
24. april 2010 - 13:25 #8
Sorry med forklaringerne.....
Det handler bare om et script som kun skal køre én gang dagligt.
Scriptet kaldes mange gange i løbet af dagen via cronjob-funktion i en Drupal-installatione, og så sker det jævnligt, at "kaldene" sker dobbelt - det vil sige indenfor samme sekund.
Dermed skal scriptet kun køres første gang, det kaldes pr. dag.

Derfor gør jeg det, at jeg smider dd. i et MySQL-felt i afslutningen af scriptet.

Afviklingen af scriptet tager måske 2 sekunder, hvorfor dd. skrives i MySQL efter ca. 2. sekunder.
Hvis så scriptet kaldes igen, inden scriptet er kørt færdigt (altså inden for de 2 sekunder), så vil scriptet kører 1 gang til, hvilket ikke må ske.

Derfor ser jeg en løsning med, at der i starten af scriptafviklingen skrives til et tjek-felt i MySQl. Det sker måske allerede efter 0,1 sekund.

Herved kan jeg styre om, scriptet er gang med afvikling (et alternativ til LOCK TABLES)

Nu prøver jeg det i hvert fald.
Avatar billede coderdk Praktikant
25. april 2010 - 18:19 #9
Hvad med bare en simpel semafor, implementeret som en fil?

if ( file_exists( "script_koerer" ) )
{
  exit;
}
touch( "script_koerer" );
// lav arbejdet her
unlink( "script_koerer" );


Evt check hvor gammel filen er?
Avatar billede nemlig Professor
26. april 2010 - 21:34 #10
Jeg mener, at det er løst ved at jeg "reserverer" filen, ved at skrive et "tjek" til MySQL. Altså en løsning, der læner sig op af showsource's forslag med at låse tabellerne.

Jeg vælger derfor at tildele pointene til showsource, hvis du venligst vil sende et svar.
Avatar billede nemlig Professor
12. august 2010 - 10:48 #11
Lukketid.....
Sender showsource et svar!
Avatar billede nemlig Professor
18. august 2010 - 17:32 #12
Showsource - hvor er du?  :)
Avatar billede nemlig Professor
24. august 2010 - 22:30 #13
Lukketid. Ellers må Showsource efterfølgende sende mig en besked, og jeg oprettet et nyt spørgsmål for at tildele pointene retteligt.
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Vi tilbyder markedets bedste kurser inden for webudvikling

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester