PHP: izvedba skripte preko cli kot sys user

Zdravo,
v lastnem sistemu delam modul za newsletter (okrožnice).
Procedura je sledeča:
- ustvari vsebino sporočila (ročno ali programatično iz drugih modulov)
- (če je narejeno ročno) nastavi prejemnike
- predogled
- dodaj v vrsto za pošiljanje

Ker je naslovnikov lahko dosti, moram php skripto za pošiljanje pognati kot sistemski uporabnik (apache/drugo) preko cli php, saj je http klient nezanesljiv.
V backendu se prikazuje napredek pošiljanja (%).
Teoretično se lahko naredi več različnih newsletterjev z več tisoč prejemniki (recimo izid 4 izdelkov na isti dan, vsem prednaročnkom moraš poslati mejl) in te bi lahko enostavno hkrati izvajal.

Problem pa imam, kako pognati ta task. Če se ne motim je edini način preko crona.
Tu bi dal cron job na vsake 2 minuti in ta bi pognal maintainance.php, tam pa bi ugotavljal, ali je kakšen newsletter v vrsti za pošiljanje.
Ta maintainance pristop bi verjetno prišel v poštev še za kakšno stvar.

Idealno pa bi bilo, če bi lahko naredil "one time only" cron job, ki se izvede kot web user potem pa izbriše. Ampak kolikor vem ni apija za upravljanje crontab, edino exec ukazov, to pa ni vedno na voljo.

Bo ok tole ali ima kdo drugi kakšen boljši predlog? :)

PS: ve kdo, kako ima npr. magento? Na tak način kot si jaz predstavljam maintaince?

8 odgovorov

Magento ima cron.sh skripto za izvajanje tovrstnih opravil, ki jo je tudi potrebno izvajati na vsake 5 min preko cronjoba.

Vsebina cron.sh datoteke, če ti kaj pomaga:

#!/bin/sh
# location of the php binary
if [ ! "$1" = "" ] ; then
CRONSCRIPT=$1
else
CRONSCRIPT=cron.php
fi

PHP_BIN=`which php`

# absolute path to magento installation
INSTALLDIR=`echo $0 | sed 's/cron\.sh//g'`

#       prepend the intallation path if not given an absolute path
if [ "$INSTALLDIR" != "" -a "`expr index $CRONSCRIPT /`" != "1" ];then
    if ! ps auxwww | grep "$INSTALLDIR""$CRONSCRIPT" | grep -v grep 1>/dev/null 2>/dev/null ; then
        $PHP_BIN "$INSTALLDIR""$CRONSCRIPT" &
    fi
else
    if  ! ps auxwww | grep " $CRONSCRIPT" | grep -v grep | grep -v cron.sh 1>/dev/null 2>/dev/null ; then
        $PHP_BIN $CRONSCRIPT &
    fi
fi
1

Pošiljat emaile takole je kar pogreb in precej neoptimalno. To se resi direktno na serverju. Ampak to spet ni trivialno za nardit.

Uporabi mailchimp ali sendgrid pa bos mel implementirano v 2h.

1

Hvala blindek za c/p, očitno imajo narejeno tako, da če ne poveš kaj za en skript bi rad pognal, požene cron.php (prej pa preveri ali se morda že izvaja).

SpinX ne vem zakaj bi bil "pogreb", če je dobro implementirano. Da bi pa strankam zraven moje cene moral prodajati še mailchimp npr. za 150 USD mesečno pa ne pridem nikamor. Uporabljam frameworke, da si vsaj malo zmanjšam količino dela, da bi pa moja aplikacija bila odvisna od zunanjih plačljivih APIjev pa si ne želim.
Na željo stranke pa se vedno lahko naredi razširitev za omenjene zadeve.

Že pošiljanje manjšega števila emailov, recimo 10k, je zelo neoptimalno, če to delaš s PHPjem. Dela že, ne bi pa rekel, da je na tak način zadeva dobro implementirana.

In z uporabo tega ne rabiš skrbet za nastavitve na strežniku, če je blacklistan IP, itd ... in zato prejemniki dejansko dobijo mail, ki ga pošlješ.

Za Amazon SES pa obstaja http://sendy.co. 59$. One time. Potem pa 0.10$ na 1000 poslanih emailov.

Tole pa ne leti nate specifično ampak moram napisat:
Opažam, da dosti developerjev špara tam kjer res nima nobenega smisla. Namesto enga google searcha in nakupa modula za 99$ gredo to delat sami, namesto uporabe plačljivih servicov to implementirajo sami... $99 so ~3 programerske ure. V treh urah ne narediš nič pametnega.

7

da ne govorimo o tem, da je SES odlicno prestudiran, tudi mailChimp...takih stvari res ni pametno na novo izumljat in rabit svoje resource

Ne želim iti v ta offtopic, zakaj delam to kar delam. Spraševal sem o tehničnem problemu. Vseeno hvala za vaše predloge. Če bom v bodoče ugotovil potrebo (in če bo kdo želel to plačati) bom naredil module za zunanje ponudnike.

1

ok, ok, naj ti bo :P

  • maile daš v vrsto za pošiljanje
  • cron lavfa na 2min
  • v cronu imaš limit, ko bereš iz vrste (zato, da ne traja pošiljanje dlje kot 2min)
  • narediš process handler, da ti ne izvede drugega crona v 4ti minuti, če prejšnji še traja
  • za process handler lahko pa najdeš primere na githubu: prvi, drugi

Upam, da pošiljaš preko smtp in ne preko mail() funkcije.

2

Ok to je načeloma porihtano.
V bistvu mora biti narejeno tako, da se lahko več taskov naenkrat dogaja (npr. supplier update par 10.000 izdelkov + pošiljanje okrožnice).
Zato sem uporabil zastavice in sicer čim ugotovi, da je potrebno pognati task, se zastavica nastavi kot "sending", tako da naslednji spawn tega več ne more pognati.
Edino še moram dodati logiko, da ugotovi, ali prejšni task ni "obupal" oz. ali sploh še pošilja, če ne da resuma naprej.
Če sem dobro razumel je ta process handler podobna zadeva, le da je ta zastavica file na disku. Še ena varianta je, da bi v samem fileu naredil "flock(FILE)" in ta isti file do odklenitve (ali restarta apacha) ne bi bil dostopen.

Edit: kako pošiljam je nastavljivo v configu (doslej povsod SMTP).