¿Cómo asegurarse de que solo se ejecute un wp_cron () a la vez?

9

Tengo alrededor de 20 wp_cron()funciones como el siguiente código. Casi todos los crons se ejecutan cada hora; Algunos son diarios.

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 el rendimiento del servidor y para no seguir recibiendo mensajes de límite de servidor de las empresas de alojamiento, quiero asegurarme de que solo se ejecute un cron en un momento dado ... ¿Es posible?


La respuesta actual aceptada es excelente, pero tengo la siguiente pregunta, es por eso que comienzo una recompensa por esta pregunta.

Por favor, lea la respuesta aceptada al principio.

Supongamos que Cron 1 se ejecuta, mi código de cron2 no se ejecutará porque todavía estamos dentro de los 5 minutos o el primer cron se está ejecutando, pero debido a que se wp_schedule_event( time(), 'hourly', 'my_task_hook' );ejecuta para cron2, creo que WordPress considera que cron2 se ejecuta ... Así que básicamente el código del código cron2 nunca se ejecuta ..... ¿O he entendido mal algo?

Soy la persona mas estupida
fuente
No, lo entiendes correctamente. Actualizaré mi respuesta con algunas soluciones para su problema ...
Krzysiek Dróżdż

Respuestas:

10

Sí, es posible...

Y para ser sincero, a menudo es muy importante hacer esto ... WP Scheduler a veces tiende a causar problemas, cuando las tareas cron son largas ...

Entonces, ¿cómo resuelvo este problema?

Utilizo la API de transitorios para implementar semáforos ...

Aquí está el 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 qué uso transitorios en este caso? Porque:

  • Son parte de WP.
  • Son fáciles de usar y eficientes.
  • No causarán puntos muertos. Digamos que mi tarea cron puede ser eliminada (puede ocurrir algún error, o se ejecuta demasiado y se mata, y así sucesivamente). En tal caso, no eliminará el semáforo, por lo que todas las tareas futuras no funcionarán. El uso de transitorios resuelve este problema, porque después de un tiempo se eliminarán los transitorios.

¿Y qué pasa si hay muchas acciones diferentes que hacer?

Entonces, digamos que hay muchas tareas cron diferentes, que nunca deberían ejecutarse al mismo tiempo, pero todavía queremos que todas se ejecuten ...

Si usamos la solución con semáforo y usamos solo un semáforo para todas estas tareas, entonces algunas de ellas nunca se ejecutarán. Entonces, ¿qué hacer entonces?

En tal caso, debe cambiar su forma de pensar. No tiene algunas tareas independientes, sino una cola de tareas que hacer. Por lo tanto, debe implementarlo de esta manera.

Entonces:

  1. Agrega algún tipo de cola (puede usar una matriz y almacenarla como opción, o agregar una tabla de base de datos personalizada).
  2. Utiliza su evento horario actual de WP cron para agregar tareas a la cola.
  3. Agrega las segundas tareas cron de WP que se ejecutan con mucha más frecuencia y "come" tareas de la cola una por una. Esta tarea "comedor" debe utilizar el semáforo para garantizar que solo se ejecute una tarea a la vez.
Krzysiek Dróżdż
fuente
Gracias, pero lo siento, nunca he usado transitorios antes ... Pero estoy tratando de entender el código. ¿Por qué configuró 5 minutos para transitorios porque elimina el transitorio usando delete_transient()? ¿Entonces ese tiempo importa? Quiero decir, cada vez que lo pones set_transient, se elimina justo después de que mi trabajo está hecho ... Entonces, ¿por qué hay un momento?
Soy la persona más estúpida
Porque pueden ocurrir algunos errores. Echa un vistazo a la última viñeta.
Krzysiek Dróżdż
Gracias, genial ... Solo una pregunta. Según tengo entendido, si uso my_task_function_semaphorecomo nombre para transitorios, ¿debo usar todos los demás cron con el mismo nombre?
Soy la persona más estúpida
@IamtheMostStupidPerson depende de lo que quieras lograr ... Si solo una tarea debe funcionar en un momento dado, entonces sí, todas las tareas deben usar el mismo nombre transitorio que el semáforo
Krzysiek Dróżdż
1
He hecho cosas similares con las herramientas de Job Queue como Gearman. Esta implementación puede ayudar: github.com/10up/WP-Minions
Fayaz