Jak upewnić się, że jednocześnie działa tylko jedna wp_cron ()?

9

Mam około 20 wp_cron()funkcji, takich jak poniższy kod. Prawie wszystkie crony biegają co godzinę; kilka jest codziennie.

if ( ! wp_next_scheduled( 'my_task_hook' ) ) {
  wp_schedule_event( time(), 'hourly', 'my_task_hook' );
}

add_action( 'my_task_hook', 'my_task_function' );

function my_task_function() {
  //Complex Code
}

Aby zwiększyć wydajność serwera, aby nie otrzymywać wiadomości o ograniczeniach serwera od firm hostingowych, chcę mieć pewność, że w danym momencie działa tylko jeden cron ... Czy to możliwe?


Obecna zaakceptowana odpowiedź jest świetna, ale mam następujące pytanie, dlatego zaczynam nagrodę za to pytanie.

Najpierw przeczytaj zaakceptowaną odpowiedź.

Załóżmy, że uruchamia się Cron 1, Mój kod cron2 nie działa, ponieważ wciąż jesteśmy w ciągu 5 minut lub pierwszy cron wciąż działa, ale z powodu wp_schedule_event( time(), 'hourly', 'my_task_hook' );uruchamiania dla cron2 Myślę, że WordPress uważa, że ​​działa cron2 ..... Więc w zasadzie kod kodu cron2 nigdy nie działa ..... Czy coś źle zrozumiałem?

Jestem najgłupszą osobą
źródło
Nie, rozumiesz to poprawnie. Zaktualizuję moją odpowiedź kilkoma rozwiązaniami twojego problemu ...
Krzysiek Dróżdż

Odpowiedzi:

10

Tak to mozliwe...

I szczerze mówiąc, często bardzo ważne jest, aby to zrobić ... WP Scheduler czasami powoduje problemy, gdy zadania CRON są długie ...

Jak więc rozwiązać ten problem?

Używam Transients API do implementacji semaforów ...

Oto kod:

if ( ! wp_next_scheduled( 'my_task_hook' ) ) {
  wp_schedule_event( time(), 'hourly', 'my_task_hook' );
}

add_action( 'my_task_hook', 'my_task_function' );

function my_task_function() {
  // if some other my_task is already running, stop
  if ( get_transient( 'my_task_function_semaphore' ) ) return;

  // set semaphore for 5 minutes
  set_transient( 'my_task_function_semaphore', true, 5*60 );

  // DO YOUR STUFF

  delete_transient( 'my_task_function_semaphore' );
}

Dlaczego w tym przypadku używam stanów nieustalonych? Ponieważ:

  • Są częścią WP.
  • Są łatwe w użyciu i wydajne.
  • Nie spowodują impasu. Powiedzmy, że moje zadanie crona może zostać zabite (może wystąpić błąd lub działa zbyt długo i zostaje zabity itd.). W takim przypadku nie usunie semafora, więc wszystkie przyszłe zadania nie będą działać. Korzystanie z transjentów rozwiązuje ten problem, ponieważ po pewnym czasie transjenty zostaną usunięte.

A jeśli będzie wiele różnych działań do zrobienia?

Powiedzmy, że istnieje wiele różnych zadań CRON, które nigdy nie powinny działać w tym samym czasie, ale nadal chcemy, aby wszystkie działały ...

Jeśli użyjemy rozwiązania z semaforem i użyjemy tylko jednego semafora dla wszystkich tych zadań, niektóre z nich mogą nigdy nie zostać uruchomione. Co więc zrobić?

W takim przypadku powinieneś zmienić swoje myślenie. Nie masz żadnych niezależnych zadań, ale kolejkę zadań do wykonania. Dlatego powinieneś wdrożyć to w ten sposób.

Więc:

  1. Dodajesz kolejkę (możesz użyć tablicy i zapisać ją jako opcję lub dodać niestandardową tabelę DB).
  2. Używasz obecnie cogodzinnego wydarzenia WP cron, aby dodawać zadania do kolejki.
  3. Dodajesz drugie zadania WP cron, które są uruchamiane znacznie częściej i „zjadają” zadania z kolejki jeden po drugim. To zadanie „zjadacz” powinno wykorzystywać semafor, aby zapewnić, że w danym momencie działa tylko jedno zadanie.
Krzysiek Dróżdż
źródło
Dzięki, ale przepraszam, nigdy wcześniej nie używałem przejściowego ... Ale staram się zrozumieć kod. Dlaczego ustawiłeś 5 minut na przejściowe, ponieważ usuwasz przejściowe za pomocą delete_transient(). Więc ten czas ma znaczenie? Mam na myśli to, który czas poświęcasz set_transient, jest usuwany zaraz po zakończeniu mojej pracy ... Dlaczego więc jest czas?
Jestem najgłupszą osobą
Ponieważ mogą wystąpić pewne błędy. Spójrz na ostatni punkt kuli.
Krzysiek Dróżdż
Dzięki, świetnie ... Tylko jedno pytanie. Jak rozumiem, jeśli używam my_task_function_semaphorejako nazwy przejściowej, muszę używać wszystkich innych cronów pod tą samą nazwą?
Jestem najgłupszą osobą
@IamtheMostStupidPerson zależy to od tego, co chcesz osiągnąć ... Jeśli tylko jedno zadanie powinno działać w danym momencie, to tak - wszystkie zadania powinny używać tej samej nazwy przejściowej co semafor
Krzysiek Dróżdż
1
Zrobiłem podobne rzeczy z narzędziami kolejki zadań, takimi jak Gearman. Ta implementacja może pomóc: github.com/10up/WP-Minions
Fayaz