diff --git a/.gitattributes b/.gitattributes index 1913eb1d4a889b764d9e977d645b782db218db6b..38bd4b0f0c6bb156cc3eedf30d1197b4bb9472da 100644 --- a/.gitattributes +++ b/.gitattributes @@ -4,6 +4,7 @@ config/ecran_securite.php -text config/remove.txt -text ecrire/action/activer_plugins.php -text ecrire/action/ajouter_lien.php -text +ecrire/action/annuler_job.php -text ecrire/action/auth.php -text ecrire/action/charger_plugin.php -text ecrire/action/confirmer_email.php -text @@ -16,6 +17,7 @@ ecrire/action/editer_liens.php -text ecrire/action/editer_objet.php -text ecrire/action/editer_rubrique.php -text ecrire/action/etre_webmestre.php -text +ecrire/action/forcer_job.php -text ecrire/action/iconifier.php -text ecrire/action/index.php -text ecrire/action/instituer_article.php -text @@ -25,10 +27,12 @@ ecrire/action/logout.php -text ecrire/action/menu_rubriques.php -text ecrire/action/preferer.php -text ecrire/action/purger.php -text +ecrire/action/purger_queue.php -text ecrire/action/redirect.php -text ecrire/action/referencer_traduction.php -text ecrire/action/reorganiser.php -text ecrire/action/session.php -text +ecrire/action/super_cron.php -text ecrire/action/supprimer_lien.php -text ecrire/action/supprimer_rubrique.php -text ecrire/action/tester.php -text @@ -139,6 +143,7 @@ ecrire/inc/prepare_recherche.php -text ecrire/inc/presentation_mini.php -text ecrire/inc/presenter_enfants.php -text ecrire/inc/puce_statut.php -text +ecrire/inc/queue.php -text ecrire/inc/recherche_to_array.php -text ecrire/inc/rechercher.php -text ecrire/inc/securiser_action.php -text @@ -701,6 +706,7 @@ prive/modeles/formulaire.html -text prive/modeles/image.html -text prive/modeles/img.html -text prive/modeles/mail_inscription.html -text +prive/modeles/object_jobs_list.html -text prive/modeles/pagination.html -text prive/modeles/pagination_page.html -text prive/modeles/pagination_page_precedent_suivant.html -text @@ -766,6 +772,7 @@ prive/squelettes/contenu/configurer_langue.html -text prive/squelettes/contenu/configurer_multilang.html -text prive/squelettes/contenu/configurer_preferences.html -text prive/squelettes/contenu/infos_perso.html -text +prive/squelettes/contenu/job_queue.html -text prive/squelettes/contenu/navigation.html -text prive/squelettes/contenu/plan.html -text prive/squelettes/contenu/recherche.html -text @@ -975,6 +982,9 @@ prive/themes/spip/images/puce-proposer-8.png -text prive/themes/spip/images/puce-publier-8.png -text prive/themes/spip/images/puce-refuser-8.png -text prive/themes/spip/images/puce-supprimer-8.png -text +prive/themes/spip/images/queue-process-16.png -text +prive/themes/spip/images/queue-process-24.png -text +prive/themes/spip/images/queue-process-32.png -text prive/themes/spip/images/racine-16.png -text prive/themes/spip/images/racine-24.png -text prive/themes/spip/images/reaction-48.png -text diff --git a/ecrire/action/annuler_job.php b/ecrire/action/annuler_job.php new file mode 100644 index 0000000000000000000000000000000000000000..87e701f7a0dfa0d8bd51921ee120e4501c973e54 --- /dev/null +++ b/ecrire/action/annuler_job.php @@ -0,0 +1,30 @@ +<?php + +/***************************************************************************\ + * SPIP, Systeme de publication pour l'internet * + * * + * Copyright (c) 2001-2011 * + * 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; + +/** + * Annuler un travail + * @return void + */ +function action_annuler_job_dist(){ + $securiser_action = charger_fonction('securiser_action','inc'); + $id_job = $securiser_action(); + + if ($id_job = intval($id_job) + AND autoriser('annuler','job',$id_job) + ){ + job_queue_remove($id_job); + } +} + +?> \ No newline at end of file diff --git a/ecrire/action/forcer_job.php b/ecrire/action/forcer_job.php new file mode 100644 index 0000000000000000000000000000000000000000..82c1def47730c9c685dac1afc512190ed40bf86b --- /dev/null +++ b/ecrire/action/forcer_job.php @@ -0,0 +1,33 @@ +<?php + +/***************************************************************************\ + * SPIP, Systeme de publication pour l'internet * + * * + * Copyright (c) 2001-2011 * + * 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; + +/** + * Executer un travaille immediatement + * @return void + */ +function action_forcer_job_dist(){ + $securiser_action = charger_fonction('securiser_action','inc'); + $id_job = $securiser_action(); + + if ($id_job = intval($id_job) + AND autoriser('forcer','job',$id_job) + ){ + include_spip('inc/queue'); + include_spip('inc/genie'); + queue_schedule(array($id_job)); + } + +} + +?> \ No newline at end of file diff --git a/ecrire/action/purger_queue.php b/ecrire/action/purger_queue.php new file mode 100644 index 0000000000000000000000000000000000000000..a9c7caff4798640bd7f987a28f2f02091bd3371a --- /dev/null +++ b/ecrire/action/purger_queue.php @@ -0,0 +1,30 @@ +<?php + +/***************************************************************************\ + * SPIP, Systeme de publication pour l'internet * + * * + * Copyright (c) 2001-2011 * + * 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; + +/** + * Purger la liste des travaux en attente + * @return void + */ +function action_purger_queue_dist(){ + $securiser_action = charger_fonction('securiser_action','inc'); + $securiser_action(); + + if (autoriser('purger','queue')){ + include_spip('inc/queue'); + queue_purger(); + } + +} + +?> \ No newline at end of file diff --git a/ecrire/action/super_cron.php b/ecrire/action/super_cron.php new file mode 100644 index 0000000000000000000000000000000000000000..de008fed276557f3e433531b45f4362a733d80f9 --- /dev/null +++ b/ecrire/action/super_cron.php @@ -0,0 +1,50 @@ +<?php + +/***************************************************************************\ + * SPIP, Systeme de publication pour l'internet * + * * + * Copyright (c) 2001-2011 * + * 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; + +/** + * Url pour lancer le cron de manière asynchrone si le serveur + * le permet + * + * On se base sur le même code que celui du pipeline affichage final + * + * Cette fonction est utile pour être appelée depuis un cron UNIX par exemple + * car elle retourne tout de suite + * + * Exemple de tache cron Unix pour un appel toutes les minutes : + * "* * * * * curl http://www.mondomaine.tld/spip.php?action=super_cron" + */ +function action_super_cron_dist(){ + // Si fsockopen est possible, on lance le cron via un socket + // en asynchrone + if(function_exists('fsockopen')){ + $url = generer_url_action('cron'); + $parts=parse_url($url); + $fp = fsockopen($parts['host'], + isset($parts['port'])?$parts['port']:80, + $errno, $errstr, 30); + if ($fp) { + $out = "GET ".$parts['path']."?".$parts['query']." HTTP/1.1\r\n"; + $out.= "Host: ".$parts['host']."\r\n"; + $out.= "Connection: Close\r\n\r\n"; + fwrite($fp, $out); + fclose($fp); + return; + } + } + // ici lancer le cron par un CURL asynchrone si CURL est présent + // TBD + + return; +} +?> \ No newline at end of file diff --git a/ecrire/base/auxiliaires.php b/ecrire/base/auxiliaires.php index 5d15bb7aa754f3b76711097820c224eb560d5bf3..e26d4318fe6fadd6a6c3bf08ce987e2459fb1b76 100644 --- a/ecrire/base/auxiliaires.php +++ b/ecrire/base/auxiliaires.php @@ -46,6 +46,16 @@ $spip_meta = array( $spip_meta_key = array( "PRIMARY KEY" => "nom"); +$spip_jobs_liens = array( + "id_job" => "bigint(21) DEFAULT '0' NOT NULL", + "id_objet" => "bigint(21) DEFAULT '0' NOT NULL", + "objet" => "VARCHAR (25) DEFAULT '' NOT NULL", +); + +$spip_documents_liens_key = array( + "PRIMARY KEY" => "id_job,id_objet,objet", + "KEY id_job" => "id_job"); + $tables_auxiliaires['spip_auteurs_liens'] = array( 'field' => &$spip_auteurs_liens, 'key' => &$spip_auteurs_liens_key); @@ -56,7 +66,10 @@ $tables_auxiliaires['spip_meta'] = array( $tables_auxiliaires['spip_resultats'] = array( 'field' => &$spip_resultats, 'key' => &$spip_resultats_key); - +$tables_auxiliaires['spip_jobs_liens'] = array( + 'field' => &$spip_jobs_liens, + 'key' => &$spip_documents_liens_key); + $tables_auxiliaires = pipeline('declarer_tables_auxiliaires',$tables_auxiliaires); } diff --git a/ecrire/base/serial.php b/ecrire/base/serial.php index 12eb0f803a85b3b44f7f0cdfb7d77313ac7cb462..ff167451030eefc38f5fded0e88132676ed1d31f 100644 --- a/ecrire/base/serial.php +++ b/ecrire/base/serial.php @@ -115,6 +115,24 @@ $spip_rubriques_key = array( ); +$spip_jobs = array( + "id_job" => "bigint(21) NOT NULL", + "descriptif" => "text DEFAULT '' NOT NULL", + "fonction" => "varchar(255) NOT NULL", //nom de la fonction + "args"=> "longblob DEFAULT '' NOT NULL", // arguments + "md5args"=> "char(32) NOT NULL default ''", // signature des arguments + "inclure" => "varchar(255) NOT NULL", // fichier a inclure ou path/ pour charger_fonction + "priorite" => "smallint(6) NOT NULL default 0", + "date" => "datetime DEFAULT '0000-00-00 00:00:00' NOT NULL", // date au plus tot + "status" => "tinyint NOT NULL default 1", + ); + +$spip_jobs_key = array( + "PRIMARY KEY" => "id_job", + "KEY date" => "date", + "KEY status" => "status", +); + /// Attention: mes_fonctions peut avoir deja defini cette variable /// il faut donc rajouter, mais pas reinitialiser @@ -124,6 +142,8 @@ $tables_principales['spip_auteurs'] = array('field' => &$spip_auteurs, 'key' => &$spip_auteurs_key,'join' => &$spip_auteurs_join); $tables_principales['spip_rubriques'] = array('field' => &$spip_rubriques, 'key' => &$spip_rubriques_key); +$tables_principales['spip_jobs'] = + array('field' => &$spip_jobs, 'key' => &$spip_jobs_key); $tables_principales = pipeline('declarer_tables_principales',$tables_principales); } diff --git a/ecrire/core.xml b/ecrire/core.xml index 2656751bf49dcc0416b9a2042ee4b16d7bdfe4fb..28d70f5e749249be86866e39c929c4be48c398d1 100644 --- a/ecrire/core.xml +++ b/ecrire/core.xml @@ -78,7 +78,11 @@ <titre>titre_admin_tech</titre> <url>admin_tech</url> </bouton> - + <bouton id="job_queue" parent='bando_administration'> + <icone>images/queue-process-16.png</icone> + <titre>queue_titre</titre> + </bouton> + <bouton id="bando_configuration"> @@ -185,6 +189,7 @@ </pipeline> <pipeline><nom>affichage_final</nom><action>f_tidy</action></pipeline> <pipeline><nom>affichage_final</nom><action>f_admin</action></pipeline> + <pipeline><nom>affichage_final</nom><action>f_queue</action></pipeline> <pipeline><nom>affichage_final_prive</nom> <action>affichage_final_prive_title_auto</action> <inclure>inc/pipelines_ecrire.php</inclure> @@ -200,7 +205,7 @@ <pipeline><nom>affiche_auteurs_interventions</nom><action></action></pipeline> <pipeline><nom>affiche_droite</nom><action></action></pipeline> <pipeline><nom>affiche_gauche</nom><action></action></pipeline> - <pipeline><nom>affiche_milieu</nom><action></action></pipeline> + <pipeline><nom>affiche_milieu</nom><action>f_queue_affiche_milieu</action></pipeline> <pipeline><nom>affiche_enfants</nom><action></action></pipeline> <pipeline><nom>affiche_hierarchie</nom><action></action></pipeline> <pipeline><nom>affiche_formulaire_login</nom> diff --git a/ecrire/inc/autoriser.php b/ecrire/inc/autoriser.php index 790e34dde0a36574fc9fd517f1512c29dd6b27d8..a1dcf5d093998e790f2690b658313b4705431a44 100644 --- a/ecrire/inc/autoriser.php +++ b/ecrire/inc/autoriser.php @@ -581,4 +581,12 @@ function autoriser_synchro_bouton_dist($faire, $type, $id, $qui, $opts){ return $qui['statut']=='0minirezo'; } -?> +/** + * Autoriser la purge de la queue : il faut etre webmestre + * @return mixed + */ +function autoriser_queue_purger_dist(){ + return autoriser('webmestre'); +} + +?> \ No newline at end of file diff --git a/ecrire/inc/genie.php b/ecrire/inc/genie.php index bb589eb2f92885b8baf54186b45e14f977dc9abb..90c0dd55f2850f14a45474442469efc4cba9737c 100644 --- a/ecrire/inc/genie.php +++ b/ecrire/inc/genie.php @@ -52,43 +52,21 @@ if (!defined('_ECRIRE_INC_VERSION')) return; // http://doc.spip.org/@inc_genie_dist function inc_genie_dist($taches = array()) { - - if (!$taches) - $taches = taches_generales(); - - // Quelle est la tache la plus urgente ? - $tache = ''; - $tmin = $t = time(); - foreach ($taches as $nom => $periode) { - $celock = _DIR_TMP . $nom . '.lock'; - $date_lock = @filemtime($celock); - if ($date_lock + $periode < $tmin) { - $tmin = $date_lock + $periode; - $tache = $nom; - $lock = $celock; - $last = $date_lock; - } - // debug : si la date du fichier est superieure a l'heure actuelle, - // c'est que les serveurs Http et de fichiers sont desynchro. - // Ca peut mettre en peril les taches cron : signaler dans le log - // (On laisse toutefois flotter sur une heure, pas la peine de s'exciter - // pour si peu) - else if ($date_lock > $t + 3600) - spip_log("Erreur de date du fichier $lock : $date_lock > $t !"); - } - if ($tache) { - spip_timer('tache'); - spip_log('cron: debut '.$tache, 'genie'); - touch($lock); - $cron = charger_fonction($tache, 'genie'); - $retour = $cron($last); - // si la tache a eu un effet : log - if ($retour) { - spip_log("cron: $tache (" . spip_timer('tache') . ") $retour", 'genie'); - if ($retour < 0) - @touch($lock, 0 - $retour); - } - } + include_spip('inc/queue'); + + if (_request('exec')=='job_queue') + return; + + $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, _L("Tache CRON $function (ASAP)"), 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 + queue_schedule(count($force_jobs)?$force_jobs:null); } // @@ -102,6 +80,10 @@ function inc_genie_dist($taches = array()) { // http://doc.spip.org/@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; @@ -109,8 +91,9 @@ function taches_generales($taches_generales = array()) { // Optimisation de la base $taches_generales['optimiser'] = 3600*48; - // cache (chaque 20 minutes => 1/16eme du repertoire cache) - $taches_generales['invalideur'] = 1200; + // cache (chaque 10 minutes => 1/16eme du repertoire cache, + // soit toutes les 2h40 sur le meme rep) + $taches_generales['invalideur'] = 600; // nouveautes if ($GLOBALS['meta']['adresse_neuf'] AND $GLOBALS['meta']['jours_neuf'] @@ -141,4 +124,52 @@ function genie_invalideur_dist($t) { return (0 - $t); return 1; } + +/** + * Une tache periodique pour surveiller les taches crons et les relancer si besoin + * quand ce cron s'execute, il n'est plus dans la queue, donc il se replanifie + * lui meme, avec last=time() + * avec une dose d'aleatoire pour ne pas planifier toutes les taches au meme moment + * + * @return int + */ +function genie_queue_watch_dist(){ + $taches = taches_generales(); + foreach($taches as $tache=>$periode){ + queue_genie_replan_job($tache,$periode,time()-round(rand(1,$periode))); + } + 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 + * @param int $priority + * priorite + * @return void + */ +function queue_genie_replan_job($function,$period,$last=null,$time=0, $priority=0){ + if (!$time){ + if (!is_null($last)) + $time = $last+$period; + else + $time=time(); + } + if (is_null($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, _L("Tache CRON $function (toutes les $period s)"), array($last), "genie/", 'function_only', $time, $priority); +} ?> diff --git a/ecrire/inc/pipelines.php b/ecrire/inc/pipelines.php index f5c6801bb78afe986d9d90cdafcb56ddae12e18f..36a428adba44f0766ce17598e5457fe5f1a204a3 100644 --- a/ecrire/inc/pipelines.php +++ b/ecrire/inc/pipelines.php @@ -111,4 +111,31 @@ function f_recuperer_fond($flux) { include_spip('inc/pipelines_ecrire'); return f_afficher_blocs_ecrire($flux); } -?> + +// gerer le lancement du cron +// si des taches sont en attentes +function f_queue(&$texte){ + + // eviter une inclusion si rien a faire + if (queue_sleep_time_to_next_job() OR defined('_DEBUG_BLOCK_QUEUE')){ + return $texte; + } + + include_spip('inc/queue'); + $code = queue_affichage_cron(); + + // si rien a afficher + // ou si on est pas dans une page html, on ne sait rien faire de mieux + if (!$code OR !$GLOBALS['html']) + return $texte; + + // inserer avant le </body> fermant si on peut, a la fin de la page sinon + if (($p=strpos($texte,'</body>'))!==FALSE) + $texte = substr($texte,0,$p).$code.substr($texte,$p); + else + $texte .= $code; + + return $texte; +} + +?> \ No newline at end of file diff --git a/ecrire/inc/pipelines_ecrire.php b/ecrire/inc/pipelines_ecrire.php index 9782ad17f7737d7ec8bc97980b78d848f426f3d3..586151a06fc8739de6e7d74e3a812f2b60fab845 100644 --- a/ecrire/inc/pipelines_ecrire.php +++ b/ecrire/inc/pipelines_ecrire.php @@ -246,6 +246,26 @@ function f_afficher_blocs_ecrire($flux) { return $flux; } +/** + * Afficher les taches en attente liees a un objet + * @param string $flux + * @return string + */ +function f_queue_affiche_milieu($flux){ + $args = $flux['args']; + $res = ""; + foreach($args as $key=>$arg){ + if (preg_match(",^id_,",$key)){ + $objet = preg_replace(',^id_,', '', $key); + $res .= recuperer_fond('modeles/object_jobs_list',array('id_objet'=>$arg,'objet'=>$objet),array('ajax'=>true)); + } + } + if ($res) + $flux['data'] = $res . $flux['data']; + + return $flux; +} + /** * Trouver l'objet qui correspond * a l'exec de l'espace prive passe en argument diff --git a/ecrire/inc/presentation_mini.php b/ecrire/inc/presentation_mini.php index eb3e33d5bd754cb2b5539f156d96e3b8e5b3a75c..bb6031be8e1f103af0640498cdc3a0771d4b6831 100644 --- a/ecrire/inc/presentation_mini.php +++ b/ecrire/inc/presentation_mini.php @@ -80,14 +80,16 @@ function liste_objets_bloques($exec,$contexte=array(),$auteur=null){ // Elle comporte une image invisible declenchant une tache de fond // http://doc.spip.org/@fin_page function fin_page(){ + include_spip('inc/pipelines'); // avec &var_profile=1 on a le tableau de mesures SQL $debug = ((_request('exec') !== 'valider_xml') AND ((_request('var_mode') == 'debug') OR $GLOBALS['tableau_des_temps'] AND isset($_COOKIE['spip_admin']))); - return '<div id="pied">' + $t = '<div id="pied">' . recuperer_fond('prive/squelettes/inclure/pied') . "</div>" . "</div></div>" // cf. div#page et div.largeur ouvertes dans conmmencer_page() . ($debug?erreur_squelette():'') . "</body></html>\n"; + return f_queue($t); } function html_tests_js(){ @@ -99,9 +101,6 @@ function html_tests_js(){ . "' width='1' height='1' alt='' /></div></noscript>\n"); } return $GLOBALS['rejoue_session'] - . '<div style="background-image: url(\'' - . generer_url_action('cron') - . '\');"></div>' . (defined('_TESTER_NOSCRIPT') ? _TESTER_NOSCRIPT : ''); } diff --git a/ecrire/inc/queue.php b/ecrire/inc/queue.php new file mode 100644 index 0000000000000000000000000000000000000000..2ba5f6ded81492da4b8a7f102cc0773bec6de579 --- /dev/null +++ b/ecrire/inc/queue.php @@ -0,0 +1,520 @@ +<?php + +/***************************************************************************\ + * SPIP, Systeme de publication pour l'internet * + * * + * Copyright (c) 2001-2009 * + * 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; + +define('_JQ_SCHEDULED',1); +define('_JQ_PENDING',0); +#define('_JQ_MAX_JOBS_EXECUTE',200); // pour personaliser le nombre de jobs traitables a chaque hit +#define('_JQ_MAX_JOBS_TIME_TO_EXECUTE',15); // pour personaliser le temps d'excution dispo a chaque hit +#define('_JQ_NB_JOBS_OVERFLOW',10000); // nombre de jobs a partir duquel on force le traitement en fin de hit pour purger + +/** + * Ajouter une tache a la file + * Les taches sont ensuites executees par date programmee croissant/priorite decroissante + * + * @param $function + * The function name to call. + * @param $description + * A human-readable description of the queued job. + * @param $arguments + * Optional array of arguments to pass to the function. + * @param $file + * Optional file path which needs to be included for $fucntion. + * @param $no_duplicate + * If TRUE, do not add the job to the queue if one with the same function and + * arguments already exists. + * If 'function_only' test of existence is only on function name (for cron job) + * @param $time + * time for starting the job. If 0, job will start as soon as possible + * @param $priority + * -10 (low priority) to +10 (high priority), 0 is the default + * @return int + * id of job + */ +function queue_add_job($function, $description, $arguments = array(), $file = '', $no_duplicate = false, $time=0, $priority=0){ + include_spip('base/abstract_sql'); + + // cas pourri de ecrire/action/editer_site avec l'option reload=oui + if (defined('_GENIE_SYNDIC_NOW')) + $arguments['id_syndic'] = _GENIE_SYNDIC_NOW; + + // serialiser les arguments + $arguments = serialize($arguments); + $md5args = md5($arguments); + + // si option ne pas dupliquer, regarder si la fonction existe deja + // avec les memes args et file + if ( + $no_duplicate + AND + sql_countsel('spip_jobs', + 'status='.intval(_JQ_SCHEDULED).' AND fonction='.sql_quote($function) + .(($no_duplicate==='function_only')?'': + ' AND md5args='.sql_quote($md5args).' AND inclure='.sql_quote($file))) + ) + return false; + + // si pas de date programee, des que possible + if (!$time) + $time = time(); + $date = date('Y-m-d H:i:s',$time); + + $id_job = sql_insertq('spip_jobs',array( + 'fonction'=>$function, + 'descriptif'=>$description, + 'args'=>$arguments, + 'md5args'=>$md5args, + 'inclure'=>$file, + 'priorite'=>max(-10,min(10,intval($priority))), + 'date'=>$date, + 'status'=>_JQ_SCHEDULED, + )); + + // une option de debug pour verifier que les arguments en base sont bons + // ie cas d'un char non acceptables sur certains type de champs + // qui coupe la valeur + if (defined('_JQ_INSERT_CHECK_ARGS') AND $id_job) { + $args = sql_getfetsel('args', 'spip_jobs', 'id_job='.intval($id_job)); + if ($args!==$arguments) { + spip_log('arguments job errones / longueur '.strlen($args)." vs ".strlen($arguments).' / valeur : '.var_export($arguments,true),'queue'); + } + } + + if ($id_job){ + queue_update_next_job_time($time); + } + + return $id_job; + +} + +/** + * Purger la file de tache + * et reprgrammer les taches periodiques + * + * @return void + */ +function queue_purger(){ + include_spip('base/abstract_sql'); + sql_delete('spip_jobs'); + sql_delete("spip_jobs_liens","id_job NOT IN (".sql_get_select("id_job","spip_jobs").")"); + include_spip('inc/genie'); + genie_queue_watch_dist(); +} + +/** + * Retirer une tache de la file d'attente + * @param int $id_job + * id de la tache a retirer + * @return bool + */ +function queue_remove_job($id_job){ + include_spip('base/abstract_sql'); + + if ($row = sql_fetsel('fonction,inclure,date','spip_jobs','id_job='.intval($id_job)) + AND $res = sql_delete('spip_jobs','id_job='.intval($id_job))){ + queue_unlink_job($id_job); + // est-ce une tache cron qu'il faut relancer ? + if ($periode = queue_is_cron_job($row['fonction'],$row['inclure'])){ + // relancer avec les nouveaux arguments de temps + include_spip('inc/genie'); + // relancer avec la periode prevue + queue_genie_replan_job($row['fonction'],$periode,strtotime($row['date'])); + } + queue_update_next_job_time(); + } + return $res; +} + +/** + * Associer une tache avec un objet + * + * @param int $id_job + * id of job to link + * @param array $objets + * can be a simple array('objet'=>'article','id_objet'=>23) + * or an array of simple array to link multiples objet in one time + */ +function queue_link_job($id_job,$objets){ + include_spip('base/abstract_sql'); + + if (is_array($objets) AND count($objets)){ + if (is_array(reset($objets))){ + foreach($objets as $k=>$o){ + $objets[$k]['id_job'] = $id_job; + } + sql_insertq_multi('spip_jobs_liens',$objets); + } + else + sql_insertq('spip_jobs_liens',array_merge(array('id_job'=>$id_job),$objets)); + } +} + +/** + * Dissocier une tache d'un objet + * + * @param int $id_job + * id of job to unlink ibject with + * @return int/bool + * result of sql_delete + */ +function queue_unlink_job($id_job){ + return sql_delete("spip_jobs_liens","id_job=".intval($id_job)); +} + +/** + * Lancer une tache decrite par sa ligne SQL + * @param array $row + * describe the job, with field of table spip_jobs + * @return mixed + * return the result of job + */ +function queue_start_job($row){ + + // deserialiser les arguments + $args = unserialize($row['args']); + if ($args===false){ + spip_log('arguments job errones '.var_export($row,true),'queue'); + $args = array(); + } + + $fonction = $row['fonction']; + if (strlen($inclure = trim($row['inclure']))){ + if (substr($inclure,-1)=='/'){ // c'est un chemin pour charger_fonction + $f = charger_fonction($fonction,rtrim($inclure,'/'),false); + if ($f) + $fonction = $f; + } + else + include_spip($inclure); + } + + if (!function_exists($fonction)){ + spip_log("fonction $fonction ($inclure) inexistante ".var_export($row,true),'queue'); + return false; + } + + spip_log("queue [".$row['id_job']."]: $fonction() start", 'queue'); + switch (count($args)) { + case 0: $res = $fonction(); break; + case 1: $res = $fonction($args[0]); break; + case 2: $res = $fonction($args[0],$args[1]); break; + case 3: $res = $fonction($args[0],$args[1], $args[2]); break; + case 4: $res = $fonction($args[0],$args[1], $args[2], $args[3]); break; + case 5: $res = $fonction($args[0],$args[1], $args[2], $args[3], $args[4]); break; + case 6: $res = $fonction($args[0],$args[1], $args[2], $args[3], $args[4], $args[5]); break; + case 7: $res = $fonction($args[0],$args[1], $args[2], $args[3], $args[4], $args[5], $args[6]); break; + case 8: $res = $fonction($args[0],$args[1], $args[2], $args[3], $args[4], $args[5], $args[6], $args[7]); break; + case 9: $res = $fonction($args[0],$args[1], $args[2], $args[3], $args[4], $args[5], $args[6], $args[7], $args[8]); break; + case 10:$res = $fonction($args[0],$args[1], $args[2], $args[3], $args[4], $args[5], $args[6], $args[7], $args[8], $args[9]); break; + default: + # plus lent mais completement generique + $res = call_user_func_array($fonction, $args); + } + spip_log("queue [".$row['id_job']."]: $fonction() end", 'queue'); + return $res; + +} + +/** + * Scheduler : + * Prend une par une les taches en attente + * et les lance, dans la limite d'un temps disponible total + * et d'un nombre maxi de taches + * + * La date de la prochaine tache a executer est mise a jour + * apres chaque chaque tache finie + * afin de relancer le scheduler uniquement quand c'est necessaire + * + * @param array $force_jobs + * list of id_job to execute when provided + */ +function queue_schedule($force_jobs = null){ + $time = time(); + if (defined('_DEBUG_BLOCK_QUEUE')) { + spip_log("_DEBUG_BLOCK_QUEUE : schedule stop",'jq'._LOG_DEBUG); + return; + } + + // rien a faire si le prochain job est encore dans le futur + if (queue_sleep_time_to_next_job() AND (!$force_jobs OR !count($force_jobs))){ + spip_log("queue_sleep_time_to_next_job",'jq'._LOG_DEBUG); + return; + } + + include_spip('base/abstract_sql'); + + if (!defined('_JQ_MAX_JOBS_TIME_TO_EXECUTE')){ + $max_time = ini_get('max_execution_time')/2; + // valeur conservatrice si on a pas reussi a lire le max_execution_time + if (!$max_time) $max_time=5; + define('_JQ_MAX_JOBS_TIME_TO_EXECUTE',min($max_time,15)); // une valeur maxi en temps. + } + $end_time = $time + _JQ_MAX_JOBS_TIME_TO_EXECUTE; + + spip_log("JQ schedule $time / $end_time",'jq'._LOG_DEBUG); + + if (!defined('_JQ_MAX_JOBS_EXECUTE')) + define('_JQ_MAX_JOBS_EXECUTE',200); + $nbj=0; + // attraper les jobs + // dont la date est passee (echus en attente), + // par odre : + // - de priorite + // - de date + // lorsqu'un job cron n'a pas fini, sa priorite est descendue + // pour qu'il ne bloque pas les autres jobs en attente + if (is_array($force_jobs) AND count($force_jobs)) + $cond = "status=".intval(_JQ_SCHEDULED)." AND ".sql_in("id_job", $force_jobs); + else { + $now = date('Y-m-d H:i:s',$time); + $cond = "status=".intval(_JQ_SCHEDULED)." AND date<".sql_quote($now); + } + + register_shutdown_function('queue_error_handler'); // recuperer les erreurs auant que possible + $res = sql_allfetsel('*','spip_jobs',$cond,'','priorite DESC,date','0,'.(_JQ_MAX_JOBS_EXECUTE+1)); + do { + if ($row = array_shift($res)){ + $nbj++; + // il faut un verrou, a base de sql_delete + if (sql_delete('spip_jobs',"id_job=".intval($row['id_job'])." AND status=".intval(_JQ_SCHEDULED))){ + #spip_log("JQ schedule job ".$nbj." OK",'jq'); + // on reinsert dans la base aussitot avec un status=_JQ_PENDING + $row['status'] = _JQ_PENDING; + $row['date'] = $time; + sql_insertq('spip_jobs', $row); + + // on a la main sur le job : + // l'executer + $result = queue_start_job($row); + + $time = time(); + queue_close_job($row, $time, $result); + } + } + spip_log("JQ schedule job end time ".$time,'jq'._LOG_DEBUG); + } while ($nbj<_JQ_MAX_JOBS_EXECUTE AND $row AND $time<$end_time); + spip_log("JQ schedule end time ".time(),'jq'._LOG_DEBUG); + + if ($row = array_shift($res)){ + queue_update_next_job_time(0); // on sait qu'il y a encore des jobs a lancer ASAP + spip_log("JQ encore !",'jq'._LOG_DEBUG); + } + else + queue_update_next_job_time(); + +} + +/** + * Terminer un job au status _JQ_PENDING : + * - le reprogrammer si c'est un cron + * - supprimer ses liens + * - le detruire en dernier + * + * @param array $row + * @param int $time + * @param int $result + */ +function queue_close_job(&$row,$time,$result=0){ + // est-ce une tache cron qu'il faut relancer ? + if ($periode = queue_is_cron_job($row['fonction'],$row['inclure'])){ + // relancer avec les nouveaux arguments de temps + include_spip('inc/genie'); + if ($result<0) + // relancer tout de suite, mais en baissant la priorite + queue_genie_replan_job($row['fonction'],$periode,0-$result/*last*/,0/*ASAP*/,$row['priorite']-1); + else + // relancer avec la periode prevue + queue_genie_replan_job($row['fonction'],$periode,$time); + } + // purger ses liens eventuels avec des objets + sql_delete("spip_jobs_liens","id_job=".intval($row['id_job'])); + // supprimer le job fini + sql_delete('spip_jobs','id_job='.intval($row['id_job'])); +} + +/** + * Recuperer des erreurs auant que possible + * en terminant la gestion de la queue + */ +function queue_error_handler(){ + // se remettre dans le bon dossier, car Apache le change parfois (toujours?) + chdir(_ROOT_CWD); + + queue_update_next_job_time(); +} + + +/** + * Tester si une tache etait une tache periodique a reprogrammer + * + * @param <type> $function + * @param <type> $inclure + * @return <type> + */ +function queue_is_cron_job($function,$inclure){ + static $taches = null; + if (strncmp($inclure,'genie/',6)==0){ + if (is_null($taches)){ + include_spip('inc/genie'); + $taches = taches_generales(); + } + if (isset($taches[$function])) + return $taches[$function]; + } + return false; +} + +/** + * Mettre a jour la date du prochain job a lancer + * Si une date est fournie (au format time unix) + * on fait simplement un min entre la date deja connue et celle fournie + * (cas de l'ajout simple + * ou cas $next_time=0 car l'on sait qu'il faut revenir ASAP) + * + * @param int $next_time + * temps de la tache ajoutee ou 0 pour ASAP + */ +function queue_update_next_job_time($next_time=null){ + static $nb_jobs_scheduled = null; + static $deja_la = false; + // prendre le min des $next_time que l'on voit passer ici, en cas de reentrance + static $next = null; + if (!is_null($next_time)){ + if (is_null($next) OR $next>$next_time) + $next = $next_time; + } + // queue_close_job peut etre reentrant ici + if ($deja_la) return; + $deja_la = true; + + include_spip('base/abstract_sql'); + $time = time(); + + // traiter les jobs morts au combat (_JQ_PENDING depuis plus de 180s) + // pour cause de timeout ou autre erreur fatale + $res = sql_allfetsel("*","spip_jobs","status=".intval(_JQ_PENDING)." AND date<".sql_quote(date('Y-m-d H:i:s',$time-180))); + if (is_array($res)) { + foreach ($res as $row) + queue_close_job($row,$time); + } + + // chercher la date du prochain job si pas connu + if (is_null($next) OR is_null(queue_sleep_time_to_next_job())){ + $date = sql_getfetsel('date','spip_jobs',"status=".intval(_JQ_SCHEDULED),'','date','0,1'); + $next = strtotime($date); + } + else { + if ($next){ + if (is_null($nb_jobs_scheduled)) + $nb_jobs_scheduled = sql_countsel('spip_jobs',"status=".intval(_JQ_SCHEDULED)." AND date<".sql_quote(date('Y-m-d H:i:s',$time))); + elseif ($next<=$time) + $nb_jobs_scheduled++; + // si trop de jobs en attente, on force la purge en fin de hit + // pour assurer le coup + if ($nb_jobs_scheduled>defined('_JQ_NB_JOBS_OVERFLOW')?_JQ_NB_JOBS_OVERFLOW:10000) + define('_DIRECT_CRON_FORCE',true); + } + } + + queue_set_next_job_time($next); + $deja_la = false; +} + + +/** + * Mettre a jour la date de prochain job + * @param int $next + */ +function queue_set_next_job_time($next) { + + // utiliser le temps courant reel plutot que temps de la requete ici + $time = time(); + + // toujours relire la valeur pour comparer, pour tenir compte des maj concourrantes + // et ne mettre a jour que si il y a un interet a le faire + // permet ausis d'initialiser le nom de fichier a coup sur + $curr_next = $_SERVER['REQUEST_TIME'] + queue_sleep_time_to_next_job(true); + if ( + ($curr_next<$time AND $next>$time) // le prochain job est dans le futur mais pas la date planifiee actuelle + OR $curr_next>$next // le prochain job est plus tot que la date planifiee actuelle + ) { + if (include_spip('inc/memoization') AND defined('_MEMOIZE_MEMORY') AND _MEMOIZE_MEMORY) { + cache_set(_JQ_NEXT_JOB_TIME_FILENAME,intval($next)); + } + else { + ecrire_fichier(_JQ_NEXT_JOB_TIME_FILENAME,intval($next)); + } + queue_sleep_time_to_next_job($next); + } + + return queue_sleep_time_to_next_job(); +} + +/** + * html a ajouter a la page pour declencher le cron + * ou rien si on a reussi a le lancer en asynchrone + * @return string + */ +function queue_affichage_cron(){ + $texte = ""; + + // rien a faire si le prochain job est encore dans le futur + if (queue_sleep_time_to_next_job() OR defined('_DEBUG_BLOCK_QUEUE')) + return $texte; + + // il y a des taches en attentes + + // Si fsockopen est possible, on lance le cron via un socket + // en asynchrone + if(function_exists('fsockopen')){ + $url = generer_url_action('cron','',false,true); + $parts=parse_url($url); + + $fp = @fsockopen($parts['host'], + isset($parts['port'])?$parts['port']:80, + $errno, $errstr, 30); + + if ($fp) { + $query = $parts['path'].($parts['query']?"?".$parts['query']:""); + $out = "GET ".$query." HTTP/1.1\r\n"; + $out.= "Host: ".$parts['host']."\r\n"; + $out.= "Connection: Close\r\n\r\n"; + fwrite($fp, $out); + fclose($fp); + return $texte; + } + } + + // ici lancer le cron par un CURL asynchrone si CURL est présent + // TBD + + // si deja force, on retourne sans rien + if (defined('_DIRECT_CRON_FORCE')) + return $texte; + // si c'est un bot + // inutile de faire un appel par image background, + // on force un appel direct en fin de hit + if ((defined('_IS_BOT') AND _IS_BOT)){ + define('_DIRECT_CRON_FORCE',true); + return $texte; + } + + // en derniere solution, on insere une image background dans la page + $texte = '<!-- SPIP-CRON --><div style="background-image: url(\'' . + generer_url_action('cron') . + '\');"></div>'; + + return $texte; +} +?> \ No newline at end of file diff --git a/ecrire/inc/utils.php b/ecrire/inc/utils.php index 2e49c22ee68215f331fad8de656376a6411db172..e81937f381d1f4aecaea526e15255b0df451ec8a 100644 --- a/ecrire/inc/utils.php +++ b/ecrire/inc/utils.php @@ -554,49 +554,129 @@ function action_cron() { include_spip('inc/headers'); http_status(204); // No Content header("Connection: close"); - cron (2); -} - -// cron() : execution des taches de fond -// Le premier argument indique l'intervalle demande entre deux taches -// par defaut, 60 secondes (quand il est appele par public.php) -// il vaut 2 quand il est appele par ?action=cron, voire 0 en urgence -// On peut lui passer en 2e arg le tableau de taches attendu par inc_genie() -// Retourne Vrai si un tache a pu etre effectuee - -// http://doc.spip.org/@cron -function cron ($gourmand=false, $taches= array()) { - - // Si on est gourmand, ou si le fichier gourmand n'existe pas - // ou est trop vieux (> 60 sec), on va voir si un cron est necessaire. - // Au passage si on est gourmand on le dit aux autres - if (spip_touch(_DIR_TMP.'cron.lock-gourmand', 60, $gourmand) - OR ($gourmand!==false)) { - - // Le fichier cron.lock indique la date de la derniere tache - // Il permet d'imposer qu'il n'y ait qu'une tache a la fois - // et 2 secondes minimum entre chaque: - // ca soulage le serveur et ca evite - // les conflits sur la base entre taches. - - if (spip_touch(_DIR_TMP.'cron.lock', - (is_int($gourmand) ? $gourmand : 2))) { - // Si base inaccessible, laisser tomber. - if (!spip_connect()) return false; - - $genie = charger_fonction('genie', 'inc', true); - if ($genie) { - $genie($taches); - // redater a la fin du cron - // car il peut prendre plus de 2 secondes. - spip_touch(_DIR_TMP.'cron.lock', 0); - return true; - } - }# else spip_log("busy"); + define('_DIRECT_CRON_FORCE',true); + cron(); +} + +/** + * cron() : execution des taches de fond + * On peut lui passer en 1er (ou 2e arg pour compat) + * le tableau de taches attendu par inc_genie() + * Retourne Vrai si un tache a pu etre effectuee + * pas de verrou ici : les verrous sont geres sur chaque tache + * a chaque execution + * + * http://doc.spip.org/@cron + * + * @param array $taches + * taches forcees + * @param array $taches_old + * taches forcees, pour compat avec ancienne syntaxe + * @return bool + */ +function cron ($taches=array(), $taches_old= array()) { + // si pas en mode cron force + // ou si base inaccessible, laisser tomber. + if (!defined('_DIRECT_CRON_FORCE') OR !spip_connect()) return false; + spip_log("cron !",'jq'._LOG_DEBUG); + if (!is_array($taches)) $taches = $taches_old; // compat anciens appels + if ($genie = charger_fonction('genie', 'inc', true)) { + $genie($taches); + return true; } return false; } +/** + * Ajout d'une tache dans la file d'attente + * + * @param $function + * The function name to call. + * @param $description + * A human-readable description of the queued job. + * @param $arguments + * Optional array of arguments to pass to the function. + * @param $file + * Optional file path which needs to be included for $fucntion. + * @param $no_duplicate + * If TRUE, do not add the job to the queue if one with the same function and + * arguments already exists. + * @param $time + * time for starting the job. If 0, job will start as soon as possible + * @param $priority + * -10 (low priority) to +10 (high priority), 0 is the default + * @return int + * id of job + */ +function job_queue_add($function, $description, $arguments = array(), $file = '', $no_duplicate = FALSE, $time=0, $priority=0) { + include_spip('inc/queue'); + return queue_add_job($function, $description, $arguments, $file, $no_duplicate, $time, $priority); +} + +/** + * Supprimer une tache de la file d'attente + * @param int $id_job + * id of jonb to delete + * @return bool + */ +function job_queue_remove($id_job){ + include_spip('inc/queue'); + return queue_remove_job($id_job); +} + +/** + * Associer une tache a un/des objets de SPIP + * @param int $id_job + * id of job to link + * @param array $objets + * can be a simple array('objet'=>'article','id_objet'=>23) + * or an array of simple array to link multiples objet in one time + */ +function job_queue_link($id_job,$objets){ + include_spip('inc/queue'); + return queue_link_job($id_job,$objets); +} + + +/** + * Renvoyer le temps de repos restant jusqu'au prochain job + * 0 si un job est a traiter + * null si la queue n'est pas encore initialise + * $force est utilisee par queue_set_next_job_time() pour maj la valeur + * - si true, force la relecture depuis le fichier + * - si int, affecte la static directement avec la valeur + * + * @staticvar int $queue_next_job_time + * @param int/bool $force_next + * @return int + */ +function queue_sleep_time_to_next_job($force=null) { + static $queue_next_job_time = -1; + if ($force===true) + $queue_next_job_time = -1; + elseif ($force) + $queue_next_job_time = $force; + + if ($queue_next_job_time==-1) { + define('_JQ_NEXT_JOB_TIME_FILENAME',_DIR_TMP . "job_queue_next.txt"); + // utiliser un cache memoire si dispo + if (include_spip('inc/memoization') AND defined('_MEMOIZE_MEMORY') AND _MEMOIZE_MEMORY) { + $queue_next_job_time = cache_get(_JQ_NEXT_JOB_TIME_FILENAME); + } + else { + $queue_next_job_time = null; + if (lire_fichier(_JQ_NEXT_JOB_TIME_FILENAME, $contenu)) + $queue_next_job_time = intval($contenu); + } + } + + if (is_null($queue_next_job_time)) + return null; + if (!$_SERVER['REQUEST_TIME']) + $_SERVER['REQUEST_TIME'] = time(); + return max(0,$queue_next_job_time-$_SERVER['REQUEST_TIME']); +} + // transformation XML des "&" en "&" // http://doc.spip.org/@quote_amp diff --git a/ecrire/inc_version.php b/ecrire/inc_version.php index 421b1ce230e43354bdd5fee0f72470398b8b0807..9ba774441169c6d47495d31034009f02c69a7a59 100644 --- a/ecrire/inc_version.php +++ b/ecrire/inc_version.php @@ -321,7 +321,7 @@ $spip_version_branche = "2.3.0-dev"; // (= numero SVN de leur derniere modif cassant la compatibilite et/ou necessitant un recalcul des squelettes) $spip_version_code = 17563; // version de la base SQL (= numero SVN de sa derniere modif) -$spip_version_base = 17563; +$spip_version_base = 17577; // version de l'interface a la base $spip_sql_version = 1; diff --git a/ecrire/lang/ecrire_fr.php b/ecrire/lang/ecrire_fr.php index 230c7e2ee3a196f9f68db987a3b67569794590b8..2955a9a58d02422fdc5bfc4f939575fb34d3d428 100644 --- a/ecrire/lang/ecrire_fr.php +++ b/ecrire/lang/ecrire_fr.php @@ -986,6 +986,14 @@ dans une couleur qui indique leur état :', 'plugins_vue_liste' => 'Liste', 'protocole_ldap' => 'Version du protocole :', +// Q +'queue_executer_maintenant' => 'Exécuter maintenant', +'queue_nb_jobs_in_queue' => '@nb@ travaux en attente', +'queue_next_job_in_nb_sec' => 'Prochain travail dans @nb@ s', +'queue_one_job_in_queue' => '1 travail en attente', +'queue_purger_queue' => 'Purger la liste des travaux', +'queue_titre' => 'Liste de travaux', + // R 'repertoire_plugins' => 'Répertoire :', diff --git a/ecrire/maj/svn10000.php b/ecrire/maj/svn10000.php index 2702b9f7c5469a79607896a20fbbf85a2c173da0..d269871e61b86bcde4f960f287d71ffdc8e2d7e4 100644 --- a/ecrire/maj/svn10000.php +++ b/ecrire/maj/svn10000.php @@ -342,4 +342,8 @@ $GLOBALS['maj'][17563] = array( array('sql_update','spip_articles',array('virtuel'=>'SUBSTRING(chapo,2)','chapo'=>"''"),"chapo LIKE '=_%'"), ); +$GLOBALS['maj'][17577] = array( + array('maj_tables',array('spip_jobs','spip_jobs_liens')), +); + ?> \ No newline at end of file diff --git a/ecrire/public.php b/ecrire/public.php index f95123f5ff001424b7ba9c07858767fbfeea0567..fa3f6f10ef0ef2cd4a4836e0582ebfc72fafe9ca 100644 --- a/ecrire/public.php +++ b/ecrire/public.php @@ -207,15 +207,8 @@ if (isset($GLOBALS['_INC_PUBLIC'])) { } // Effectuer une tache de fond ? - // si #SPIP_CRON est present, on ne le tente que pour les navigateurs - // en mode texte (par exemple), et seulement sur les pages web - if (defined('_DIRECT_CRON_FORCE') - OR ( - !defined('_DIRECT_CRON_INHIBE') - AND $html - AND !strstr($page['texte'], '<!-- SPIP-CRON -->') - AND !preg_match(',msie|mozilla|opera|konqueror,i', $_SERVER['HTTP_USER_AGENT'])) - ) + // si _DIRECT_CRON_FORCE est present, on force l'appel + if (defined('_DIRECT_CRON_FORCE')) cron(); // sauver le cache chemin si necessaire diff --git a/ecrire/public/balises.php b/ecrire/public/balises.php index 2c3e93e58f1083cd78909c85f1c7b67e6c366084..0e9cc0987cbe576c3d1bfb075fa0358b68857159 100644 --- a/ecrire/public/balises.php +++ b/ecrire/public/balises.php @@ -330,20 +330,6 @@ function balise_FIN_SURLIGNE_dist($p) { } -// #SPIP_CRON -// a documenter -// insere un <div> avec un lien background-image vers les taches de fond. -// Si cette balise est presente sur la page de sommaire, le site ne devrait -// quasiment jamais se trouver ralenti par des taches de fond un peu lentes -// http://doc.spip.org/@balise_SPIP_CRON_dist -function balise_SPIP_CRON_dist ($p) { - $p->code = '"<!-- SPIP-CRON --><div style=\"background-image: url(\'' . - generer_url_action('cron') . - '\');\"></div>"'; - $p->interdire_scripts = false; - return $p; -} - // #INTRODUCTION // #INTRODUCTION{longueur} // http://www.spip.net/@introduction diff --git a/prive/modeles/object_jobs_list.html b/prive/modeles/object_jobs_list.html new file mode 100644 index 0000000000000000000000000000000000000000..ad7025788d15bea614872fa96105456c222b3933 --- /dev/null +++ b/prive/modeles/object_jobs_list.html @@ -0,0 +1,17 @@ +<B_jobs> + <div class="jobs_liste jobs_liste_#ENV{objet}"> + #ANCRE_PAGINATION + <ul class="liste_items jobs"> + <BOUCLE_jobs(JOBS){par date}{pagination 5}{objet}{id_objet}> + <li class="item"> + <div class="date">[(#DATE|date_relative)]</div> + [<strong class="description">(#DESCRIPTIF|PtoBR)</strong>] + [(#AUTORISER{'annuler','job',#ID_JOB}|oui) + <div class="actions">[(#BOUTON_ACTION{<:annuler:>,#URL_ACTION_AUTEUR{annuler_job,#ID_JOB,#SELF},ajax})]</div> + ] + </li> + </BOUCLE_jobs> + </ul> + [<p class="pagination">(#PAGINATION)</p>] + </div> +</B_jobs> \ No newline at end of file diff --git a/prive/squelettes/contenu/job_queue.html b/prive/squelettes/contenu/job_queue.html new file mode 100644 index 0000000000000000000000000000000000000000..e4a0c7a8f333493452ddbdfd67a06fa0cc7a59bf --- /dev/null +++ b/prive/squelettes/contenu/job_queue.html @@ -0,0 +1,41 @@ +#CACHE{0} +[(#AUTORISER{administrer,queue}|sinon_interdire_acces)] +<?php +// bloquer la queue sur ce hit +// pour avoir coherence entre l'affichage de la liste de jobs +// et les jobs en base en fin de hit +define('_DEBUG_BLOCK_QUEUE',true); +include_spip('inc/genie'); +genie_queue_watch_dist(); +?> +<h1><:queue_titre:></h1> +<B_jobs> + <h3>[(#GRAND_TOTAL|singulier_ou_pluriel{queue_one_job_in_queue,queue_nb_jobs_in_queue})]</h3> + <p>#SET{nb,#REM|queue_sleep_time_to_next_job}<:queue_next_job_in_nb_sec{nb=#GET{nb}}:></p> + [<p class="pagination">(#PAGINATION{prive})</p>] + <ul class="liste-items"> + <BOUCLE_jobs(jobs){par date}{pagination 20}> + <li class="item[ (#STATUS|?{'scheduled','pending'})]"> + <div class="date">[(#DATE|date_relative)][ (#STATUS|non)(en cours)][(#PRIORITE|oui)[#PRIORITE]]</div> + [<strong class="description">(#DESCRIPTIF|PtoBR)</strong>] + [<span class="small">| #FONCTION((#ARGS|unserialize|implode{','}))</span>] + [(#AUTORISER{'annuler','job',#ID_JOB}|oui) + <div class="actions"> + [(#BOUTON_ACTION{<:annuler:>,#URL_ACTION_AUTEUR{annuler_job,#ID_JOB,#SELF},ajax})] + [(#BOUTON_ACTION{<:queue_executer_maintenant:>,#URL_ACTION_AUTEUR{forcer_job,#ID_JOB,#SELF},ajax})] + </div> + ] + </li> + </BOUCLE_jobs> + </ul> + [<p class="pagination">(#PAGINATION{prive})</p>] + [(#AUTORISER{'purger','queue'}|oui) + <div class="actions"> + [(#BOUTON_ACTION{<:queue_purger_queue:>,#URL_ACTION_AUTEUR{purger_queue,'',#SELF},ajax})] + </div> + ] +</B_jobs> +<script type="text/javascript">/*<![CDATA[*/ +function queue_reload(){jQuery('h1').ajaxReload();} +if (window.jQuery) setTimeout(queue_reload,60000); +/*]]>*/</script> \ No newline at end of file diff --git a/prive/themes/spip/images/queue-process-16.png b/prive/themes/spip/images/queue-process-16.png new file mode 100644 index 0000000000000000000000000000000000000000..54805d4d9875ac5bd10194a74d685721aae72a33 Binary files /dev/null and b/prive/themes/spip/images/queue-process-16.png differ diff --git a/prive/themes/spip/images/queue-process-24.png b/prive/themes/spip/images/queue-process-24.png new file mode 100644 index 0000000000000000000000000000000000000000..e55cd17cdd1f6282ce1fedc0907054f3f186b8f2 Binary files /dev/null and b/prive/themes/spip/images/queue-process-24.png differ diff --git a/prive/themes/spip/images/queue-process-32.png b/prive/themes/spip/images/queue-process-32.png new file mode 100644 index 0000000000000000000000000000000000000000..da5b0d5eb929bae9c23a856913eeea89e9ea0677 Binary files /dev/null and b/prive/themes/spip/images/queue-process-32.png differ