Como garantir que apenas um wp_cron () seja executado por vez?

9

Eu tenho cerca de 20 wp_cron()funções como o código a seguir. Quase todos os crons funcionam a cada hora; alguns são diários.

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
}

Para aumentar o desempenho do servidor e não continuar recebendo mensagens de limite de servidor das empresas de hospedagem, quero garantir que apenas um cron seja executado em um determinado momento ... É possível?


A resposta atual aceita é ótima, mas tenho a seguinte pergunta, é por isso que começo uma recompensa por essa pergunta.

Por favor, leia a resposta aceita primeiro.

Vamos supor que o Cron 1 seja executado, meu código do cron2 não funcionará porque ainda estamos dentro dos 5 minutos ou o primeiro cron ainda está em execução, mas por causa da wp_schedule_event( time(), 'hourly', 'my_task_hook' );execução do cron2, acho que o WordPress considera o cron2 executado ..... Então, basicamente, codifica do código cron2 nunca roda ..... Ou entendi algo errado?

Eu sou a pessoa mais estúpida
fonte
Não, você entendeu corretamente. Atualizarei minha resposta com algumas soluções para o seu problema ...
Krzysiek Dróżdż

Respostas:

10

Sim, é possível...

E para ser sincero, geralmente é muito importante fazer isso ... O WP Scheduler às vezes tende a causar problemas, quando as tarefas cron são longas ...

Então, como eu resolvo esse problema?

Eu uso a API de transientes para implementar semáforos ...

Aqui está o código:

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' );
}

Por que eu uso transitórios neste caso? Porque:

  • Eles fazem parte do WP.
  • Eles são fáceis de usar e eficientes.
  • Eles não causam impasses. Digamos que minha tarefa cron possa ser morta (pode ocorrer algum erro, ou ela demora muito e é morta, e assim por diante). Nesse caso, ele não excluirá o semáforo, portanto, todas as tarefas futuras não funcionarão. O uso de transientes resolve esse problema, porque após algum tempo o transitório será excluído.

E se houver muitas ações diferentes para fazer?

Então, digamos que existem muitas tarefas cron diferentes, que nunca devem ser executadas ao mesmo tempo, mas ainda queremos que todas sejam executadas ...

Se usarmos a solução com semáforo e usar apenas um semáforo para todas essas tarefas, algumas delas poderão nunca ser executadas. Então o que fazer então?

Nesse caso, você deve mudar seu pensamento. Você não tem algumas tarefas independentes, mas uma fila de tarefas a serem executadas. Portanto, você deve implementá-lo dessa maneira.

Assim:

  1. Você adiciona algum tipo de fila (você pode usar uma matriz e armazená-la como opção ou adicionar uma tabela de banco de dados personalizada).
  2. Você usa seu evento horário do WP no momento para adicionar tarefas à fila.
  3. Você adiciona as segundas tarefas cron do WP, que são executadas com muito mais frequência e "consome" tarefas da fila, uma por uma. Essa tarefa "comedora" deve usar o semáforo para garantir que apenas uma tarefa seja executada por momento.
Krzysiek Dróżdż
fonte
Obrigado, mas desculpe, nunca usei transitório antes ... Mas estou tentando entender o código. Por que você definiu 5 minutos para transitório porque exclui o transitório usando delete_transient(). Então esse tempo importa? Quero dizer, sempre que você dedica set_transient, é excluído logo após o final do meu trabalho ... Então, por que há um tempo?
Eu sou a pessoa mais idiota
Porque alguns erros podem ocorrer. Dê uma olhada no último ponto de bala.
Krzysiek Dróżdż
Obrigado, ótimo ... Apenas uma pergunta. Pelo que entendi, se eu usar my_task_function_semaphorecomo o nome de transitório, devo usar todos os outros crons com o mesmo nome?
Eu sou a pessoa mais idiota
@IamtheMostStupidPerson isso depende do que você quer alcançar ... Se apenas uma tarefa devem trabalhar em dado momento, então sim - todas as tarefas devem usar o mesmo nome transitória como semáforo
Krzysiek Drozdz
11
Fiz coisas semelhantes com ferramentas da fila de tarefas, como o Gearman. Esta implementação pode ajudar: github.com/10up/WP-Minions
Fayaz