WP Cron nu execută când timpul s-a scurs

27 mar. 2013, 17:12:16
Vizualizări: 22K
Voturi: 19

Obiectivul

Vreau să folosesc wp_schedule_single_event( ) pentru a executa un eveniment singular care să-mi trimită un e-mail la 8 minute după ce utilizatorul trimite un formular.

Problema

Următorul cod este în fișierul meu functions.php:

function nkapi_send_to_system( $args ) {
  wp_mail( 'xxx', 'xxx', $args );
}

add_action( 'nkapi_send', 'nkapi_send_to_system' );

function schedule_event( $id ) {
  wp_schedule_single_event( current_time( 'timestamp' ) + 480, 'nkapi_send', array( $id ) );
}

Și următorul cod este folosit pentru a apela schedule-event:

schedule_event( $_SESSION['insert_id'] ); // variabila $_SESSION conține un INT

După ce am așteptat mai mult de 8 minute nu am primit niciun e-mail în inbox.

Ce am încercat

Cu plugin-ul Core Control este posibil să vezi ce sarcini cron sunt programate.

Ecranul Core Control pentru vizualizarea sarcinilor cron programate

După câteva modificări am reușit să le configurez corect și, mai mult, când apăs "Run Now", primesc într-adevăr un e-mail în inbox.

Dar de ce nu se execută sarcinile cron când vizitez site-ul meu după 8 minute. Ce ar putea fi greșit în acest cod? Trebuie să menționez că este prima dată când folosesc WP Cron.

Am încercat mai mult

După comentariul lui vancoder am decis să testez dacă codul funcționează dacă pun următorul cod direct în functions.php:

function schedule_event( $id ) {
  wp_schedule_single_event( time(), 'nkapi_send', array( $id ) );
}

if ( isset( $_SESSION['insert_id'] ) ) {
  if ( ! array_key_exists( 'insert_scheduled', $_SESSION ) || $_SESSION['insert_scheduled'] != $_SESSION['insert_id'] ) {
    schedule_event( $_SESSION['insert_id'] );
    $_SESSION['insert_scheduled'] = $_SESSION['insert_id'];
  }
}

Dezavantajul acestui cod este că utilizatorul trebuie să meargă pe altă pagină înainte ca acest cod să fie executat. Dar pe de altă parte, nici acesta nu funcționează, așa că aceasta nu ar fi prima mea problemă...

5
Comentarii

Unde și cum este declanșat schedule_event( $_SESSION['insert_id'] );?

vancoder vancoder
27 mar. 2013 18:23:31

Un shortcode include un fișier separat (care conține un formular) într-o pagină, atunci când acel formular este trimis, pagina se reîncarcă, același fișier apoi execută schedule_event( ), să zicem în partea de sus a fișierului inclus încărcat de shortcode.

Mike Madern Mike Madern
28 mar. 2013 09:48:50

Funcționează vreun cron? wp_version_check etc?

vancoder vancoder
28 mar. 2013 19:28:37

Nu am reușit să fac niciun cron să funcționeze. Care ar putea fi problema?

Mike Madern Mike Madern
29 mar. 2013 10:09:15

Pentru a confirma - nici măcar joburile cron de bază nu funcționează?

vancoder vancoder
4 apr. 2013 19:44:42
Toate răspunsurile la întrebare 6
8
18

În primul rând, definește programările personalizate pentru joburile cron.

add_filter('cron_schedules', array($this, 'cron_schedules'));

public function cron_schedules($schedules){
    $prefix = 'cron_';// Evită conflictele cu alte joburi cron. Exemplu de referință: cron_30_mins
    $schedule_options = array(
        '30_mins' => array(
            'display' => '30 de minute',
            'interval' => '1800'
        ),
        '1_hours' => array(
            'display' => 'Oră',
            'interval' => '3600'
        ),
        '2_hours' => array(
            'display' => '2 ore',
            'interval' => '7200'
        )
    );
    /* Adaugă fiecare programare personalizată în sistemul de joburi cron. */
    foreach($schedule_options as $schedule_key => $schedule){
        $schedules[$prefix.$schedule_key] = array(
            'interval' => $schedule['interval'],
            'display' => __('La fiecare '.$schedule['display'])
        );
     }
     return $schedules;
}

Trebuie să decizi unde și când să programezi efectiv evenimentul.

Iată un exemplu de fragment de cod care face un apel către o metodă personalizată a unei clase:

$schedule = $this->schedule_task(array(
    'timestamp' => current_time('timestamp'), // Determină când să programezi sarcina.
    'recurrence' => 'cron_30_mins',// Alege una dintre programările definite anterior.
    'hook' => 'custom_imap_import'// Setează numele jobului tău cron.
));

Iată codul care programează efectiv evenimentul:

private function schedule_task($task){
    /* Trebuie să existe informații despre sarcină. */
    if(!$task){
        return false;
    }
    /* Setează lista de chei necesare pentru sarcină. */
    $required_keys = array(
        'timestamp',
        'recurrence',
        'hook'
    );
    /* Verifică existența informațiilor necesare pentru sarcină. */
    $missing_keys = array();
    foreach($required_keys as $key){
        if(!array_key_exists($key, $task)){
            $missing_keys[] = $key;
        }
    }
    /* Verifică cheile lipsă. */
    if(!empty($missing_keys)){
        return false;
    }
    /* Sarcina nu trebuie să fie deja programată. */
    if(wp_next_scheduled($task['hook'])){
        wp_clear_scheduled_hook($task['hook']);
    }
    /* Programează sarcina să ruleze. */
    wp_schedule_event($task['timestamp'], $task['recurrence'], $task['hook']);
    return true;
}

Acum, tot ce trebuie să faci este să apelezi numele jobului tău cron personalizat. În acest exemplu, numele jobului cron este custom_imap_import.

add_action('custom_imap_import', array($this, 'do_imap_import'));

public function do_imap_import(){
    // .... Execută acțiuni când cron este declanșat ....
}

Deci, în acest exemplu, $this->do_imap_import(); este apelat la fiecare 30 de minute (presupunând că site-ul tău are suficient trafic).


Note

Este necesară o vizită pe pagină pentru ca jobul cron să se declanșeze la intervalele corecte.

Exemplu: Dacă ai programat o sarcină să ruleze la fiecare 30 de minute, dar nimeni nu vizitează site-ul timp de 4 ore, jobul cron nu va fi declanșat decât atunci când un vizitator accesează site-ul după acele 4 ore. Dacă chiar ai nevoie ca sarcina să fie executată la fiecare 30 de minute, este recomandat să configurezi un job cron real prin furnizorul de hosting pentru a accesa site-ul la intervalele dorite.

Joburile cron WordPress nu încetinesc site-ul!

Poate te întrebi ce se întâmplă dacă scriptul cron durează mult timp pentru a fi executat, vor trebui vizitatorii să aștepte până când scriptul se termină. Nu! Cum este posibil acest lucru? Dacă te uiți în fișierul wp-cron.php, vei găsi linia

ignore_user_abort(true);

Este o configurare php.ini care specifică că, dacă oprești încărcarea site-ului/scriptului, scriptul nu se va opri din execuție.

Dacă te uiți în fișierul wp-includes/cron.php, vei găsi o linie similară cu aceasta:

wp_remote_post( $cron_url, 
array('timeout' => 0.01,
 'blocking' => false, 
 'sslverify' => apply_filters('https_local_ssl_verify', true)) );

Aceasta înseamnă că WordPress va aștepta doar 0.01 secunde pentru a declanșa execuția, apoi va întrerupe, dar, deoarece ai setat ignore_user_abort la true, scriptul va continua să ruleze. Această funcționalitate este un avantaj major pentru executarea scripturilor mari în cadrul joburilor cron WordPress.

Funcții disponibile pentru ajutor:

4 apr. 2013 17:22:45
Comentarii

Acesta este un răspuns remarcabil de amplu, care, din câte văd, nu abordează întrebarea reală - și anume de ce toate sarcinile programate (inclusiv cele de bază) eșuează.

vancoder vancoder
4 apr. 2013 19:40:42

Acest răspuns are rolul de a ghida utilizatorul în direcția corectă pentru înțelegerea și programarea corectă a sarcinilor cron în WordPress.

Michael Ecklund Michael Ecklund
4 apr. 2013 20:07:54

Acest lucru m-a ajutat foarte mult să înțeleg programările cron în WordPress.

Mike Madern Mike Madern
9 apr. 2013 16:08:17

Michael, ar trebui să răspunzi mai des. Foarte bun +1

kaiser kaiser
3 oct. 2013 05:36:35

În ce moment ar trebui să faci "add_action('custom_imap_import', array($this, 'do_imap_import'))", presupunând o clasă de plugin? În constructor?

codecowboy codecowboy
11 oct. 2013 20:25:13

@codecowboy Da, sau undeva unde poate fi încărcat când cron-ul este pregătit să fie declanșat.

Michael Ecklund Michael Ecklund
21 oct. 2013 23:12:25

Core oferă deja un interval hourly, așa că nu este nevoie să folosești 1_hours.

Ian Dunn Ian Dunn
25 nov. 2014 03:06:29

Cred că WP_Cron utilizează GMT în fundal, la fel ca restul WP, așa că ar fi mai bine să programezi primul eveniment la time() în loc de current_time().

Ian Dunn Ian Dunn
25 nov. 2014 03:09:08
Arată celelalte 3 comentarii
2

Mai întâi, te rog confirmă dacă nu ai activat niciun plugin de caching. Plugin-urile de caching pot interfera cu job-urile cron deoarece vizitatorii tăi nu primesc o pagină live, ci o versiune cache a paginii.

Dacă ai un plugin de caching activat, poți alege una dintre paginile tale și să adaugi o excepție în setările plugin-ului de caching pentru acea pagină, astfel încât să nu fie niciodată cache-uită.

Apoi, va trebui să creezi manual un job cron (folosind cpanel dacă ești pe un mediu de hosting partajat sau din terminal dacă e un server VPS/dedicat) care să viziteze acea pagină la fiecare câteva minute.

Sper că te ajută!

5 apr. 2013 17:59:13
Comentarii

Am un plugin de caching activat! Mai precis W3 Total Cache

Mike Madern Mike Madern
9 apr. 2013 16:04:55

Există opțiuni pentru a dezactiva întregul cache, dar nu văd nicio opțiune pentru a activa/dezactiva cache-ul doar pentru plugin-uri

user1019042 user1019042
2 nov. 2020 21:53:06
1

WordPress Cron vă permite să programați sarcini, dar acestea vor fi executate doar dacă se face o cerere către site. Pentru fiecare cerere pe care o primește WordPress, acesta va verifica dacă există job-uri cron de procesat și, dacă da, va trimite o cerere asincronă către /wp-cron.php?doing_wp_cron pentru a procesa job-ul. Dacă momentul programat al unui job trece fără ca să se facă vreo cerere, atunci procesul cron nu va fi pornit.

Deoarece puteți vedea și rula job-urile programate, este posibil să nu existe cereri care să declanșeze pornirea job-ului cron, mai ales dacă utilizați un plugin de caching. Cea mai bună opțiune pentru a descărca acest proces pe un program mai regulat este să dezactivați verificarea implicită din WordPress și să folosiți crontab.

Mai întâi, pentru a dezactiva verificarea implicită (ceea ce poate ajuta puțin cu performanța pe partea clientului), adăugați următoarele în wp-config.php:

// Dezactivează verificarea implicită pentru job-urile cron WordPress la încărcarea paginilor
define( 'DISABLE_WP_CRON', true );

Apoi, creați o sarcină care să acceseze pagina wp-cron.php o dată pe minut pentru a procesa orice job-uri în fundal. Din linia de comandă, introduceți crontab -e și apoi adăugați o linie care arată astfel:

*/1 * * * * /usr/bin/curl --silent http://example.com/wp-cron.php?doing_wp_cron=$(date +\%s.\%N) >/dev/null 
6 apr. 2013 03:43:17
Comentarii

Dacă nu dai o valoare pentru doing_wp_cron, există o probabilitate mare ca job-urile să fie executate uneori de două ori. Folosește doing_wp_cron=$(date +\%s.\%N) pentru a preveni acest lucru.

Alexander Garden Alexander Garden
10 nov. 2013 13:04:14
0

Pentru cei care protejează site-ul lor (de dezvoltare) de accesul public, Autentificarea HTTP poate fi cauza pentru care WP Cron nu funcționează.

În cazul în care poate ajuta pe cineva, iată lista mea de lucruri pe care le-am făcut înainte de a identifica și a înțelege cerințele WP Cron:

  • Am observat că evenimentele erau programate corect și puteau fi rulate folosind WP-CLI.
  • Și, de asemenea, am observat că accesarea /wp-cron.php?doing_wp_cron prin browser a declanșat execuții, așa cum a fost sugerat în 13625.
  • Documentația oficială a fost citită.
  • M-am asigurat că DISABLE_WP_CRON nu era setat.
  • Și am aflat că ALTERNATE_WP_CRON era o soluție de rezervă reușită, dar nesatisfăcătoare.
  • Pentru a exclude bug-uri de regresie, am încercat să instalez câteva versiuni mai vechi de WordPress.
  • Toate plugin-urile au fost dezactivate și tema a fost schimbată la cea implicită, pentru a izola problema.
  • Oamenii au menționat termenul loopbacks, dar lipsind erori sau avertismente legate de acesta, l-am considerat irelevant.
  • În cele din urmă, am găsit o întrebare cu un răspuns care explica efectiv cum să debug-ui cron.
  • După ce am atașat Xdebug la wp_cron(), am putut vedea că execuția se termina în wp_remote_post(), care eșua clar.

Când am știut ce să caut, am găsit acest articol minunat despre cauzele problemelor WP Cron de Jeff Starr. La finalul acestuia, el face trimitere la plugin-ul său wp-cron-http-auth.

17 iun. 2020 10:37:19
1

Verifică dacă DISABLE_WP_CRON nu este setat în configurarea ta.

Dacă nu este cazul, încearcă să dezactivezi toate plugin-urile (cu excepția core control - deși aș folosi wp-crontrol) și verifică dacă job-urile de bază funcționează. Dacă da, înseamnă că există o interferență din partea unui plugin.

De asemenea, încearcă să treci la o temă standard twentysomething.

Dacă niciuna dintre aceste soluții nu funcționează, probabil este o problemă de hosting.

4 apr. 2013 20:19:23
Comentarii

Nu am setat DISABLE_WP_CRON în fișierul meu wp-config.php, voi încerca mai multe variante și revin mai târziu

Mike Madern Mike Madern
9 apr. 2013 16:07:21
0

Verifică orice plugin care ascunde WordPress.

Cum să vezi dacă acesta este problema?

  1. Navighează la http(s)://siteultau.com/wp-cron.php Ar trebui să vezi o pagină goală. Complet goală.
  2. În plus, trebuie să vezi în managerul de cron jobs o oră sub "Next execution": Cron job programat - dacă wp-cron.php funcționează corect (nu doar textul "In queue" - ci o oră specifică - pentru unele intrări "In queue" este OK uneori, dar dacă este singurul lucru pe care îl vezi -> cron-ul tău nu funcționează.)

+1. Nu crede orice plugin care "verifică dacă cron funcționează" - de exemplu, WP Cron status checker plugin a arătat că cron funcționează. Dar, de fapt, nu funcționa. Orice ar arăta - crede-ți ochii și nu acest plugin!

Concluzie: Dacă primești eroare 404 - atunci dezactivează a) nu doar pluginurile de caching, așa cum sugerează alții b) ci și orice pluginuri care ascund WordPress.

16 apr. 2019 00:45:30