spip_nursit/ecrire/inc/genie.php
2023-06-01 17:30:12 +02:00

229 lines
7.6 KiB
PHP
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
* Copyright (c) 2001-2019 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
* Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne. *
\***************************************************************************/
if (!defined('_ECRIRE_INC_VERSION')) {
return;
}
/**
* Gestion des tâches de fond
*
* Deux difficultés :
* - la plupart des hebergeurs ne fournissent pas le Cron d'Unix
* - les scripts usuels standard sont limites à 30 secondes
*
* Solution
* --------
* Toute connexion à SPIP s'achève par un appel (asynchrone si possible)
* à la fonction `cron()` qui appelle la fonction surchargeable `inc_genie_dist()`
*
* Sa définition standard ci-dessous prend dans une liste de tâches
* la plus prioritaire.
*
* Une fonction exécutant une tâche doit retourner un nombre :
* - nul, si la tache n'a pas à être effecutée
* - positif, si la tache a été effectuée
* - négatif, si la tache doit être poursuivie ou recommencée
*
* Elle recoit en argument la date de la dernière exécution de la tâche.
*
* On peut appeler cette fonction avec d'autres tâches (pour étendre SPIP)
* spécifiée par des fonctions respectant le protocole ci-dessus.
*
* On peut ajouter des tâches périodiques ou modifier la fréquence
* de chaque tâche et leur priorité en utilisant le pipeline
* `taches_generales_cron`.
*
* On peut également directement en déclarer avec la balise `genie` d'un paquet.xml
* de plugin, tel que `<genie nom="nom_de_la_tache" periode="86400" />`
*
* @package SPIP\Core\Genie
**/
/**
* Prévoit l'exécution de la tâche cron la plus urgente
*
* Les tâches sont dans un tableau `'nom de la tâche' => périodicité`
*
* Cette fonction exécute la tache la plus urgente, c'est à dire
* celle dont la date de dernière exécution + la périodicité est minimale.
*
* La date de la prochaîne exécution de chaque tâche est indiquée dans la
* table SQL `spip_jobs`
*
* La fonction exécutant la tâche est (généralement) un homonyme de préfixe "genie_".
* Le fichier homonyme du repertoire "genie/" est automatiquement lu
* et il est supposé définir cette fonction.
*
* @uses queue_add_job() Lorsqu'une tâche est à forcer
* @uses queue_schedule()
* @see taches_generales() Liste des tâches déclarées
*
* @param array $taches
* Tâches dont on force maintenant l'exécution le plus tôt possible.
* Sinon, prendra la tâche la plus prioritaire.
* @return
**/
function inc_genie_dist($taches = array()) {
include_spip('inc/queue');
if (_request('exec') == 'job_queue') {
return false;
}
$force_jobs = array();
// l'ancienne facon de lancer une tache cron immediatement
// etait de la passer en parametre a ing_genie_dist
// on reroute en ajoutant simplement le job a la queue, ASAP
foreach ($taches as $function => $period) {
$force_jobs[] = queue_add_job($function, _T('tache_cron_asap', array('function' => $function)),
array(time() - abs($period)), "genie/");
}
// et on passe la main a la gestion de la queue !
// en forcant eventuellement les jobs ajoute a l'instant
return queue_schedule(count($force_jobs) ? $force_jobs : null);
}
//
// Construction de la liste des taches.
// la cle est la tache,
// la valeur le temps minimal, en secondes, entre deux memes taches
// NE PAS METTRE UNE VALEUR INFERIEURE A 30
// les serveurs Http n'accordant en general pas plus de 30 secondes
// a leur sous-processus
//
// http://code.spip.net/@taches_generales
function taches_generales($taches_generales = array()) {
// verifier que toutes les taches cron sont planifiees
// c'est une tache cron !
$taches_generales['queue_watch'] = 3600 * 24;
// MAJ des rubriques publiques (cas de la publication post-datee)
// est fait au coup par coup a present
// $taches_generales['rubriques'] = 3600;
// Optimisation de la base
$taches_generales['optimiser'] = 3600 * 48;
// cache (chaque 10 minutes => 1/16eme du repertoire cache,
// soit toutes les 2h40 sur le meme rep)
$taches_generales['invalideur'] = 600;
// nouveautes
if (isset($GLOBALS['meta']['adresse_neuf']) and $GLOBALS['meta']['adresse_neuf']
and $GLOBALS['meta']['jours_neuf']
and ($GLOBALS['meta']['quoi_de_neuf'] == 'oui')
) {
$taches_generales['mail'] = 3600 * 24 * $GLOBALS['meta']['jours_neuf'];
}
// maintenance (ajax, verifications diverses)
$taches_generales['maintenance'] = 3600 * 2;
// verifier si une mise a jour de spip est disponible (2 fois par semaine suffit largement)
$taches_generales['mise_a_jour'] = 3 * 24 * 3600;
return pipeline('taches_generales_cron', $taches_generales);
}
// Pas de fichier a part pour une fonction aussi petite:
// - elle peut retirer les fichiers perimes
// - elle fait appliquer le quota
// En cas de quota sur le CACHE/, nettoyer les fichiers les plus vieux
// http://code.spip.net/@genie_invalideur_dist
function genie_invalideur_dist($t) {
include_spip('inc/invalideur');
$encore = appliquer_quota_cache();
// si le cache est trop gonfle, redemander la main pour poursuivre
if ($encore) {
return (0 - $t);
}
return 1;
}
/**
* Une tâche périodique pour surveiller les tâches crons et les relancer si besoin
*
* Quand ce cron s'execute, il n'est plus dans la queue, donc il se replanifie
* lui même, avec last=time()
* avec une dose d'aleatoire pour ne pas planifier toutes les taches au meme moment
*
* @uses taches_generales()
* @uses queue_genie_replan_job()
*
* @return int
*/
function genie_queue_watch_dist() {
static $deja_la = false;
if ($deja_la) {
return;
} // re-entrance si l'insertion des jobs echoue (pas de table spip_jobs a l'upgrade par exemple)
$deja_la = true;
$taches = taches_generales();
$programmees = sql_allfetsel('fonction', 'spip_jobs', sql_in('fonction', array_keys($taches)));
$programmees = array_map('reset', $programmees);
foreach ($taches as $tache => $periode) {
if (!in_array($tache, $programmees)) {
queue_genie_replan_job($tache, $periode, time() - round(rand(1, $periode)), 0);
}
}
$deja_la = false;
return 1;
}
/**
* Replanifier une tache periodique
*
* @param string $function
* nom de la fonction a appeler
* @param int $period
* periodicite en secondes
* @param int $last
* date du dernier appel (timestamp)
* @param int $time
* date de replanification
* si null calculee automaitquement a partir de $last et $period
* si 0 = asap mais on n'insere pas le job si deja en cours d'execution
* @param int $priority
* priorite
* @return void
*/
function queue_genie_replan_job($function, $period, $last = 0, $time = null, $priority = 0) {
static $done = array();
if (isset($done[$function])) {
return;
}
$done[$function] = true;
if (is_null($time)) {
$time = time();
if ($last) {
$time = max($last + $period, $time);
}
}
if (!$last) {
$last = $time - $period;
}
spip_log("replan_job $function $period $last $time $priority", 'queue');
include_spip('inc/queue');
// on replanifie un job cron
// uniquement si il n'y en a pas deja un avec le meme nom
// independament de l'argument
queue_add_job($function, _T('tache_cron_secondes', array('function' => $function, 'nb' => $period)), array($last),
"genie/", 'function_only', $time, $priority);
}