Kdyby/Console a puštené cronu

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
wicked
Člen | 290
+
0
-

Zdravím Vás,

mám menší dotaz, jak mám nastavit do cronu aby pustilo danou věc?

Mám CronCommand.php

<?php

namespace App\Console;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Nette;
use App\Model;
use Nette\Mail\SmtpMailer;
use Nette\Mail\Message;
use Tracy\Debugger;

class CronCommand extends Command {

    /** @var \App\Model\CronModel @inject */
    public $cron;

    protected function configure() {
        $this->setName('cron')->setDescription('Zápis cron úloh');
    }

    protected function execute(InputInterface $input, OutputInterface $output) {

        try {
            $cron = $this->cron->findAll();
            foreach ($cron as $c) {
                if ($c->start == new Nette\Utils\DateTime()) {
                    try {
                        $mail = new Message();
                        $mail->setFrom('info@jirickajakub.cz');
                        $mail->addTo('jiricka.kuba@gmail.com');
                        $mail->setSubject('Pokus cron emailu');
                        $mail->setBody('A obsah který už jeeee! :)' . new Nette\Utils\DateTime());

                        $mailer = new Nette\Mail\SendmailMailer();
                        $mailer->send($mail);
                    } catch (Nette\Mail\SmtpException $ex) {
                        Debugger::log($ex, Debugger::ERROR);
                        throw $ex;
                    }
                }
            }

            $output->writeLn('<info>[OK] - cron</info>');
            return 0; // zero return code means everything is ok
        } catch (\Exception $exc) {
            $output->writeLn('<error>cron - ' . $exc->getMessage() . '</error>');
            return 1; // non-zero return code means error
        }
    }

}

Když to pustím normálně na serveru (vlastní server) pomocí

php /var/www/index.php cron

Tak vše jede jak má, ale zaboha mě nejde to pustit automaticky pomocí cronu …

Zkoušel jsem crontap -e a nastavit to samé co tady, nic se neprovedlo ( ani když jsem dal do else větve to samé, aby mě aspoň chodilo něco …)

Dále jsem to zkoušel přec ISPConfig cron ale také nic …

Jak to mám správně tedy odkazovat?

Mockrát děkuji :)

ještě config:

extensions:
    console: Kdyby\Console\DI\ConsoleExtension

console:
    url: http://mailer.jirickajakub.cz
    commands:
        - App\Console\CronCommand

Editoval wicked (1. 3. 2015 12:09)

Jan Endel
Člen | 1016
+
0
-

nemá to být crontab -e?

wicked
Člen | 290
+
0
-

Samozdřejmně, přepsal jsem se zde na foru …

Ale problém to neřeší … pořád se to nespustí … ani kdyz do else vetve pridam take posilani emailu al s textem o necasovem odeslani …

wicked
Člen | 290
+
0
-

Už vím kde je error …

problém nastává zde

$datetime = new Nette\Utils\DateTime();
            foreach ($cron as $c) {
                if ($c->start == $datetime) {

Respektivě když to mám vytvořeno tahle, datum dosazen do $datetime tak to nic neudělá …

ale jakmile jej zapíši natvrdo

$c->start == '2014-03-01 14:28:00'

Tak to vše proběhne … $datetime je ve zprávném formátu jako záznam v DB …

Vůbec mě nenapadá, kde může být chyba…

wicked
Člen | 290
+
0
-

Nikoho nenapadá v čem může být problém? Já jsem snad vyzkoušel už vše …

wicked
Člen | 290
+
0
-

Aha … tak mame změnu … vubec to nebere toto:

if ($c->start == '2015-03-01 18:05:00') {

teď mě to cron posílá každou minutu …

Co sakra dělám blbě? Když tam dám === tak to zase vůbec nepošle …

Quinix
Člen | 108
+
0
-

A co jako očekáváš od té podmínky?

if ($c->start == new Nette\Utils\DateTime()) {`

za Datetime se ti dosadí instance s aktuálním časem a to se porovná s tím co se vytáhne z databáze. Pokud to $c->start není DateTime nebo se liší, tak ti to nic neudělá…

wicked
Člen | 290
+
0
-

Od té podmínky očekávám to, že když čas v DB bude stejny jako aktualni cas, který beru pomoci new Nette\Utils\DateTime() tak se provede ta podmínka …

v DB je start normalne datetime a ma stejny format ktery by mel byt …

jak jinak by jsi chtel udelat to, aby se ti ten mail poslal jenom v tu dobu, kterou mas nastavenou v DB?

a proc me to ted funguje tak, ze me chodi email kazdou minutu, kdyz se ta podminka nerovna zaznamu v DB?

Editoval wicked (1. 3. 2015 19:15)

Filip Klimeš
Nette Blogger | 156
+
0
-

Co takhle porovnávat místo dvou objektů stringy?

$now = new \Nette\Utils\DateTime();
if ($c->start->format('Y-m-d H:i') === $now->format('Y-m-d H:i')) { ... }

Jak často pouštíš CRON? Tohle Ti podle mě bude zbytečně vytěžovat server. Lepší by možná bylo místo DB napsat různé commandy pro různé akce a čas si pak nastavit v crontabu.

wicked
Člen | 290
+
0
-

Cron mám puštěny * * * * * * * takze porad, ale akce ktere budou vykonavane v DP (zpracovani cronu) bude nahodne …

wicked
Člen | 290
+
0
-

A ano, porovnani stringu byl dobry napad, toto funguje …

Nerozumim moc tomu, proc to nefungovalo jak to mam ja, ale děkuji za radu! :-)

Filip Procházka
Moderator | 4668
+
0
-

A nebylo by lepší mít několik různých commandů, kde každý by měl jiný úkol a v crontabu by sis nastavil, který se má kdy spouštět?

wicked
Člen | 290
+
0
-

Bohužel mě nenapadá jak řešit to co potřebuji.

V db mám uložen záznam cronu, který obsahuje čas a to, co má provést.

Jedná se o rozesílání emailových kampaní v určitý čas na určitě adresy s určitou kampaní, takže čas je zde nutný takto dodržovat.

Vem si, že budu rozesílat 5 kampaní a každá bude v jiném čase, proto to mám řešeno takto :)

Pokud Vás napadne něco jiného, rád se poučim :)

llook
Člen | 407
+
0
-

Nefungovalo ti to proto, že v DB máš čas třeba 12:00, ale aktuální čas je třeba 12:00:01.

Lepší by bylo porovnávat, jestli čas z DB je mezi aktuálním časem a časem posledního spuštění toho cronu (někam si ten čas ukládat), protože co když ti to pár minut z jakéhokoli důvodu nepojede? Je žádoucí, aby v takovém případě naplánovaná akce vůbec neproběhla?

leninzprahy
Člen | 150
+
+1
-

Mě přijde jednodušší mít v db, krom času kdy se to má provést, i příznak jestli se to provedlo (třeba jako datum odeslání). V tom Commandu pak najdeš všechny záznamy, které už se měly odeslat, ale ještě nejsou odeslané (WHERE start < NOW() AND sent IS NULL), ty zpracuješ a nastavíš jim příznak odeslání (sent = NOW()).

Pak ten cron můžeš spouštět jak často potřebuješ, a on ti zpracuje, jen to co má…

leninzprahy
Člen | 150
+
0
-

Nepřijde mi jako dobrý nápad spoléhat na to, že když máš v db uložen čas spuštění např. 13:30:00, že se i ten command provede přesně ve 13:30:00. Stačí, když se spustí v 13:30:02, a už se nic nepošle…

Filip Procházka
Moderator | 4668
+
0
-

Jo, to je dobrý use-case :)

wicked
Člen | 290
+
0
-

Děkuji :)

wicked
Člen | 290
+
0
-

Jenže já to v DB právě měl uložené také pomocí Nette\Utils\Datetime(), takže i DB byla ve stylu
2015-03-30 15:00:01

V tom problém nebyl :)

Jinak vyřešené to mám tak, že když se ta cron úloha neprovede, hodí to error do adminu a upozorní na neúspěšné spuštění, takže bude již na obsluze, aby jej nastavila znovu

leninzprahy
Člen | 150
+
0
-

Zápis v cronu * * * * * * * ale znamená každou minutu, ne pořád! A nikdo ti nezaručí, že se spustí přesně v 2015–03–30 15:00:01, může se spustit 2015–03–30 15:00:03, nebo taky 2015–03–30 15:00:04 a pak už ti ta podmínka neprojde…

wicked
Člen | 290
+
0
-

To je dobrá připomínka! :)

Děkuji!

EDIT: jak jinak to tedy poustet … neukladat do DB vteriny ale jen minuty? Bude to pak pracovat jak v 15:20:00 tak v 15:20:59 ?

Editoval wicked (2. 3. 2015 18:26)

leninzprahy
Člen | 150
+
0
-

A co zkusit to označování za odeslané ?
Z výhod například:

  • Vyhneš se procházení všech historických i budoucích záznamů, protože si vybereš jen ty, které je zrovna potřeba rozeslat,
  • když se stroj z nějakého důvodu zasekne, po spuštění automaticky provede to, co mělo být provedeno,
  • můžeš zkontrolovat, co a kdy se doopravdy provedlo.