wp-cron: WordPress a basso consumo con le Azure Function

Per chi di noi (e non solo) utilizza il noto blog WordPress ha sicuramente visto il file wp-cron nella lista di quelli presente nella cartella radice. Vi siete mai chiesti a cosa serve?

wp-cron: chi sei?

Proverò a spiegarvi brevemente lo scopo del file in questione. Ad ogni visita sul nostro sito viene scatenato questo file ed ha il compito di svolgere le azioni “cron” interne al nostro sito. In sito con pochi accessi giornalieri il problema non si pone, ma se il sito riceve molti accessi (e magari contemporaneamente) le risorse del server possono essere messe a dura prova.

Caso di studio:

Ad inizio 2019 mi chiama un cliente e mi dice di avere notato un rallentamento nel sito e non capiva il motivo. La sera ho guardato lo stato delle risorse e mi sono accorto che nel pomeriggio vi era stato un alto picco di consumo CPU. Indagando ho scoperto il colpevole. Indovinate di chi si trattava? Il file wp-cron e così per risolvere il problema l’ho disabilitato pur sapendo che tra le azioni svolte dal nostro amico c’è la possibilità di “abilitare” i post con programmazione futura.

file wp-config.php define(‘DISABLE_WP_CRON’, ‘true’);

Passano due o giorni e mi arriva un messaggio WhatsApp per chiedermi come mai i post futuri risultano con la dicitura “Programmazione Saltata” e la mia risposta è stata “Stasera risolvo tutto, sono stato io il colpevole”

Soluzione “fast” wp-cron da cron

Come prima soluzione per arginare il danno ho messo un task schedulato all’interno del server con cadenza oraria per chiamare automaticamente il file e dare avvio ai diversi processi.

wget -q -O - http://propriosito.com/wp-cron.php?doing_wp_cron >/dev/null 2>&1

La soluzione è stata rapida, veloce e non bella dal mio punto di vista.

wp-cron & Azure Functions (Soluzione Elegante)

Come appena detto, la soluzione del Cron Job non mi piaceva per nulla. Il perchè? Col Job appena messo il wp-cron verrebbe eseguito ogni ora a prescindere. E se lo schedulassi al bisogno? Ossia quando un post programmato per il “future” deve essere reso visibile? Ecco la mia idea in QUATTRO punti

  1. Hook nel file function.php

  2. In questo hook SE E SOLO SE la data del post è futura viene scatenata una Azure Function di tipo HTTP Trigger passando i dati del post via query string

  3. Una volta che la function riceve i parametri effettua delle logiche su di essi e mette la richiesta in una “CloudQueue

  4. A questo punto una nuova Azure Function di tipo  “Queue Trigger” resterà in ascolto per ricevere l’url del wp-cron.php che chiamerà tramite HttpClient.

Quali sono i vantaggi di questa soluzione? Il principale che il lavoro del cron (Job Server) non verrà più sfruttato riducendo il consumo di CPU. Inoltre alcuni server “low cost” ti danno delle restrizioni molto seccanti a tema.

Esito finale? Il cliente è contento. Ora non ha nulla da preoccuparsi ed una volta programmati i post essi verranno mostrati alla data ed ora corretta (più uno scarto di 5 minuti messo da me per sicurezza evitando disallineamenti di orari)

Codice Sorgente:

Di seguito riporto parte del codice sorgente sviluppato per questa soluzione:

  • functions.php: Hook per le azioni da fare al salvataggio di un post ( Codice Completo)

  • Azure Function - QueueTrigger: In questa function è presente a chiamata minimale da fare al file wp-cron.php. L’indirizzo completo è presente all’interno della coda e lo potete leggere all’interno  della variabile myQueueItem

Manca qualcosa? Si, la function chiamata dal wordpress (AzureFunctionName) alla quale si passano i parametri. In questa parte di codice dovrete “solamente” prendere l’orario di pubblicazione ed inserire un messaggio all’interno della coda per l’orario desiderato.

functions.php

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

<?php

function scheduled_cron_on_azure_function( $post_id ) {

	$postStatus = get_post_status ( $post_id );
	
	if($postStatus != "future"){
		return;
	}

	$azureUrl = "https://devandreacarratta.azurewebsites.net/api/AzureFunctionName";
	$azureUrl .= "&DomainName=NomeDominioCliente" ;
	$azureUrl .= "&postYear=" .  get_the_date( 'Y', $post_id );
	$azureUrl .= "&postMonth=" .  get_the_date( 'n', $post_id );
	$azureUrl .= "&postDay=" .  get_the_date( 'd', $post_id );
	$azureUrl .= "&postHour=" .  get_the_date( 'H', $post_id );
	$azureUrl .= "&postMinute=" .  get_the_date( 'i', $post_id );

$r = wp_safe_remote_post( $azureUrl );	

}
add_action( 'save_post', 'scheduled_cron_on_azure_function' );

?>

Azure Function - QueueTrigger

1
2
3
4
5
6
7
8

        [FunctionName("WPCronDo")]
        public static void Run([QueueTrigger("NomeCoda", Connection = "StorageId")]string myQueueItem, ILogger log)
        {
            HttpClient httpClient = new HttpClient();
            httpClient.GetAsync(myQueueItem).Wait();
        }