From 0f9b3bcc27e7daf7d605a7a38310a8f62b9a76e8 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Sat, 17 Apr 2010 03:13:30 -0400 Subject: [PATCH] [feature/system-cron] Refactored cron task naming, loading and running. PHPBB3-9596 --- phpBB/includes/cron.php | 164 ---------------- phpBB/includes/{ => cron}/cron_lock.php | 0 phpBB/includes/cron/cron_manager.php | 175 ++++++++++++++++++ phpBB/includes/{ => cron}/cron_task.php | 0 phpBB/includes/{ => cron}/cron_task_base.php | 0 phpBB/includes/cron/cron_task_wrapper.php | 68 +++++++ phpBB/includes/cron/standard.php | 163 ---------------- .../tasks/core}/prune_all_forums.php | 2 +- .../tasks/core}/prune_forum.php | 2 +- .../standard => cron/tasks/core}/queue.php | 2 +- .../tasks/core}/tidy_cache.php | 2 +- .../tasks/core}/tidy_database.php | 2 +- .../tasks/core}/tidy_search.php | 2 +- .../tasks/core}/tidy_sessions.php | 2 +- .../tasks/core}/tidy_warnings.php | 2 +- phpBB/includes/functions.php | 7 +- phpBB/viewforum.php | 8 +- 17 files changed, 261 insertions(+), 340 deletions(-) delete mode 100644 phpBB/includes/cron.php rename phpBB/includes/{ => cron}/cron_lock.php (100%) create mode 100644 phpBB/includes/cron/cron_manager.php rename phpBB/includes/{ => cron}/cron_task.php (100%) rename phpBB/includes/{ => cron}/cron_task_base.php (100%) create mode 100644 phpBB/includes/cron/cron_task_wrapper.php delete mode 100644 phpBB/includes/cron/standard.php rename phpBB/includes/{cron_tasks/standard => cron/tasks/core}/prune_all_forums.php (95%) rename phpBB/includes/{cron_tasks/standard => cron/tasks/core}/prune_forum.php (96%) rename phpBB/includes/{cron_tasks/standard => cron/tasks/core}/queue.php (96%) rename phpBB/includes/{cron_tasks/standard => cron/tasks/core}/tidy_cache.php (93%) rename phpBB/includes/{cron_tasks/standard => cron/tasks/core}/tidy_database.php (92%) rename phpBB/includes/{cron_tasks/standard => cron/tasks/core}/tidy_search.php (96%) rename phpBB/includes/{cron_tasks/standard => cron/tasks/core}/tidy_sessions.php (91%) rename phpBB/includes/{cron_tasks/standard => cron/tasks/core}/tidy_warnings.php (94%) diff --git a/phpBB/includes/cron.php b/phpBB/includes/cron.php deleted file mode 100644 index b9a1bb778a..0000000000 --- a/phpBB/includes/cron.php +++ /dev/null @@ -1,164 +0,0 @@ -tasks as $cron_type => $params) - { - $params['object'] = $object; - $this->tasks[$cron_type] = $params; - } - } - } - } - - function is_valid_task($cron_type) - { - return isset($this->tasks[$cron_type]); - } - - function is_task_runnable($cron_type, $args=null) - { - global $config; - $time_now = time(); - $cron_params = $this->tasks[$cron_type]; - if ($cron_params['enable_config'] && !$config[$cron_params['enable_config']]) - { - return false; - } - if ($cron_param['custom_condition']) - { - $callable = array($cron_params['object'], $cron_type . '_condition'); - if ($args) - { - $answer = call_user_func_array($callable, $args); - } else - { - $answer = call_user_func($callable); - } - if (!$answer) - { - return false; - } - } - if ($time_now - $config[$cron_params['interval_config']] > $config[$cron_params['last_run_config']]) - { - return true; - } - return false; - } - - function is_task_shutdown_function_compatible($cron_type) - { - $cron_params = $this->tasks[$cron_type]; - if (isset($cron_params['shutdown_function_condition'])) - { - return call_user_func(array($cron_params->object, $cron_type . '_shutdown_function_condition')); - } else - { - return true; - } - } - - function determine_cron_mode_param() - { - global $config; - if ($config['use_system_cron']) - { - $mode = 'run_from_system'; - } else - { - $mode_param = 'run_from_phpbb'; - } - return $mode_param; - } - - function find_one_runnable_task() - { - $mode_param = $this->determine_cron_mode_param(); - foreach ($this->tasks as $cron_type => $cron_params) - { - if ($cron_params[$mode_param] && $this->is_task_runnable($cron_type)) - { - return $cron_type; - } - } - return null; - } - - function find_all_runnable_tasks() - { - $mode_param = $this->determine_cron_mode_param(); - $tasks = array(); - foreach ($this->tasks as $cron_type => $cron_params) - { - if ($cron_params[$mode_param] && $this->is_task_runnable($cron_type)) - { - $tasks[] = $cron_type; - } - } - return $tasks; - } - - function generate_task_code($cron_type, $args=array()) - { - $cron_params = $this->tasks[$cron_type]; - if ($cron_params['custom_code']) - { - $code = call_user_func_array(array($cron_params['object'], $cron_type . '_code'), $args); - } else - { - $code = $this->generate_generic_task_code($cron_type); - } - return $code; - } - - function generate_generic_task_code($cron_type) - { - global $phpbb_root_path, $phpEx; - return 'cron'; - } - - function run_task($cron_type) - { - call_user_func(array($this->tasks[$cron_type]['object'], 'run_' . $cron_type)); - } -} diff --git a/phpBB/includes/cron_lock.php b/phpBB/includes/cron/cron_lock.php similarity index 100% rename from phpBB/includes/cron_lock.php rename to phpBB/includes/cron/cron_lock.php diff --git a/phpBB/includes/cron/cron_manager.php b/phpBB/includes/cron/cron_manager.php new file mode 100644 index 0000000000..5ee06ac102 --- /dev/null +++ b/phpBB/includes/cron/cron_manager.php @@ -0,0 +1,175 @@ +find_cron_task_files(); + $this->load_tasks($task_files); + } + + /** + * Finds cron task files. + * + * A cron task file must follow the naming convention: + * includes/cron/tasks/$mod/$name.php. + * $mod is core for tasks that are part of phpbb. + * Modifications should use their name as $mod. + * $name is the name of the cron task. + * Cron task is expected to be a class named cron_task_${mod}_${name}. + * + * Todo: consider caching found task file list in global cache. + */ + public function find_cron_task_files() + { + global $phpbb_root_path, $phpEx; + + $tasks_root_path = $phpbb_root_path . 'includes/cron/tasks'; + $dir = opendir($tasks_root_path); + $task_dirs = array(); + while (($entry = readdir($dir)) !== false) + { + // ignore ., .. and dot directories + // todo: change is_dir to account for symlinks + if ($entry[0] == '.' || !is_dir($entry)) + { + continue; + } + $task_dirs[] = $entry; + } + closedir($dir); + + $ext = '.' . $phpEx; + $ext_length = strlen($ext); + $task_files = array(); + foreach ($task_dirs as $task_dir) + { + $path = $phpbb_root_path . 'includes/cron/tasks/' . $task_dir; + $dir = opendir($path); + while (($entry = readdir($dir)) !== false && substr($entry, -$ext_length) == $ext) + { + $task_file = substr($entry, 0, -$ext_length); + $task_files[] = array($task_dir, $task_file); + } + closedir($dir); + } + return $task_files; + } + + /** + * Checks whether $name is a valid identifier, and therefore part of valid cron task class name. + */ + public function is_valid_name($name) + { + return preg_match('/^[a-zA-Z][a-zA-Z0-9_]*$/', $name); + } + + public function load_tasks($task_files) + { + global $phpbb_root_path, $phpEx; + + foreach ($task_files as $task_file) + { + list($mod, $filename) = $task_file; + if ($this->is_valid_name($mod) && $this->is_valid_name($filename)) + { + include_once($phpbb_root_path . "includes/cron/$mod/$filename.$phpEx"); + $class = "cron_task_${mod}_${filename}"; + $object = new $class; + $this->tasks[] = $object; + } + } + } + + /** + * Finds a task that is ready to run. + * + * If several tasks are ready, any one of them could be returned. + */ + function find_one_ready_task() + { + foreach ($this->tasks as $task) + { + if ($task->is_ready()) + { + return $task; + } + } + return null; + } + + /** + * Finds all tasks that are ready to run. + */ + function find_all_ready_tasks() + { + $tasks = array(); + foreach ($this->tasks as $task) + { + if ($task->is_ready()) + { + $tasks[] = $task; + } + } + return $tasks; + } + + /** + * Finds a task by name. + * + * Web runner uses this method to resolve names to tasks. + */ + function find_task($name) + { + foreach ($this->tasks as $task) + { + if ($task->get_name() == $name) + { + return $task; + } + } + return null; + } + + function instantiate_task($name, $args) + { + $task = $this->find_task($name); + if ($task) + { + $class = get_class($task); + $task = new $class($args); + } + return $task; + } + + function generate_generic_task_code($cron_type) + { + global $phpbb_root_path, $phpEx; + return 'cron'; + } +} diff --git a/phpBB/includes/cron_task.php b/phpBB/includes/cron/cron_task.php similarity index 100% rename from phpBB/includes/cron_task.php rename to phpBB/includes/cron/cron_task.php diff --git a/phpBB/includes/cron_task_base.php b/phpBB/includes/cron/cron_task_base.php similarity index 100% rename from phpBB/includes/cron_task_base.php rename to phpBB/includes/cron/cron_task_base.php diff --git a/phpBB/includes/cron/cron_task_wrapper.php b/phpBB/includes/cron/cron_task_wrapper.php new file mode 100644 index 0000000000..3919e4f049 --- /dev/null +++ b/phpBB/includes/cron/cron_task_wrapper.php @@ -0,0 +1,68 @@ +task = $task; + } + + /** + * Returns whether the wrapped task is ready to run. + * + * A task is ready to run when it is runnable according to current configuration + * and enough time has passed since it was last run. + */ + public function is_ready() + { + return $this->task->is_runnable() && $this->task->should_run(); + } + + /** + * Returns the name of wrapped task. + */ + public function get_name() + { + $class = get_class($this->task); + return preg_replace('/^cron_task_/', '', $class); + } + + public function get_url() + { + global $phpbb_root_path, $phpEx; + + $name = $this->get_name(); + $url = append_sid($phpbb_root_path . 'cron.' . $phpEx, 'cron_type=' . $name); + return $url; + } + + /** + * Forwards all other method calls to the wrapped task implementation. + */ + public function __call($name, $args) + { + return call_user_func_array(array($this->task, $name), $args); + } +} diff --git a/phpBB/includes/cron/standard.php b/phpBB/includes/cron/standard.php deleted file mode 100644 index 1cb8738f17..0000000000 --- a/phpBB/includes/cron/standard.php +++ /dev/null @@ -1,163 +0,0 @@ - array( - 'custom_condition' => true, - 'run_from_system' => true, - ), - 'prune_forum' => array( - 'custom_condition' => true, - 'custom_code' => true, - ), - 'queue' => array( - 'custom_condition' => true, - 'interval_config' => 'queue_interval_config', - 'last_run_config' => 'last_queue_run', - 'run_from_phpbb' => true, - 'run_from_system' => true, - 'shutdown_function_condition' => true, - ), - 'tidy_cache' => array( - 'custom_condition' => true, - 'interval_config' => 'cache_gc', - 'last_run_config' => 'cache_last_gc', - 'run_from_phpbb' => true, - 'run_from_system' => true, - ), - 'tidy_database' => array( - 'interval_config' => 'database_gc', - 'last_run_config' => 'database_last_gc', - 'run_from_phpbb' => true, - 'run_from_system' => true, - ), - 'tidy_search' => array( - 'interval_config' => 'search_gc', - 'last_run_config' => 'search_last_gc', - 'run_from_phpbb' => true, - 'run_from_system' => true, - ), - 'tidy_sessions' => array( - 'interval_config' => 'session_gc', - 'last_run_config' => 'session_last_gc', - 'run_from_phpbb' => true, - 'run_from_system' => true, - ), - 'tidy_warnings' => array( - 'enable_config' => 'warnings_expire_days', - 'interval_config' => 'warnings_gc', - 'last_run_config' => 'warnings_last_gc', - 'run_from_phpbb' => true, - 'run_from_system' => true, - ), - ); - - function prune_forum_condition($forum_data) { - return $forum_data['enable_prune'] && $forum_data['prune_next'] < time(); - } - - function prune_forum_code($forum_id) { - global $phpbb_root_path, $phpEx; - return 'cron'; - } - - function run_prune_forum() { - } - - function queue_condition() { - global $phpbb_root_path, $phpEx; - return file_exists($phpbb_root_path . 'cache/queue.' . $phpEx); - } - - function queue_shutdown_function_condition() { - global $config; - return !$config['smtp_delivery']; - } - - function run_queue() { - global $phpbb_root_path, $phpEx; - include_once($phpbb_root_path . 'includes/functions_messenger.' . $phpEx); - $queue = new queue(); - $queue->process(); - } - - function tidy_cache_condition() { - global $cache; - return method_exists($cache, 'tidy'); - } - - function run_tidy_cache() { - global $cache; - $cache->tidy(); - } - - function run_tidy_database() { - include_once($phpbb_root_path . 'includes/functions_admin.' . $phpEx); - tidy_database(); - } - - function tidy_search_condition() { - global $phpbb_root_path, $phpEx, $config; - - // Select the search method - $search_type = basename($config['search_type']); - - return file_exists($phpbb_root_path . 'includes/search/' . $search_type . '.' . $phpEx); - } - - function run_tidy_search() { - global $phpbb_root_path, $phpEx, $config, $error; - - // Select the search method - $search_type = basename($config['search_type']); - - include_once("{$phpbb_root_path}includes/search/$search_type.$phpEx"); - - // We do some additional checks in the module to ensure it can actually be utilised - $error = false; - $search = new $search_type($error); - - if (!$error) { - $search->tidy(); - } - } - - function run_tidy_sessions() { - global $user; - $user->session_gc(); - } - - function run_tidy_warnings() { - include_once($phpbb_root_path . 'includes/functions_admin.' . $phpEx); - tidy_warnings(); - } -} diff --git a/phpBB/includes/cron_tasks/standard/prune_all_forums.php b/phpBB/includes/cron/tasks/core/prune_all_forums.php similarity index 95% rename from phpBB/includes/cron_tasks/standard/prune_all_forums.php rename to phpBB/includes/cron/tasks/core/prune_all_forums.php index 569752dcb0..13286de2b0 100644 --- a/phpBB/includes/cron_tasks/standard/prune_all_forums.php +++ b/phpBB/includes/cron/tasks/core/prune_all_forums.php @@ -25,7 +25,7 @@ if (!defined('IN_PHPBB')) * * @package phpBB3 */ -class prune_all_forums_cron_task extends cron_task_base +class cron_task_core_prune_all_forums extends cron_task_base { /** * Runs this cron task. diff --git a/phpBB/includes/cron_tasks/standard/prune_forum.php b/phpBB/includes/cron/tasks/core/prune_forum.php similarity index 96% rename from phpBB/includes/cron_tasks/standard/prune_forum.php rename to phpBB/includes/cron/tasks/core/prune_forum.php index f4ef2ea6dd..4925447162 100644 --- a/phpBB/includes/cron_tasks/standard/prune_forum.php +++ b/phpBB/includes/cron/tasks/core/prune_forum.php @@ -25,7 +25,7 @@ if (!defined('IN_PHPBB')) * * @package phpBB3 */ -class prune_forum_cron_task extends cron_task_base implements parametrized_cron_task +class cron_task_core_prune_forum extends cron_task_base implements parametrized_cron_task { /** * Constructor. diff --git a/phpBB/includes/cron_tasks/standard/queue.php b/phpBB/includes/cron/tasks/core/queue.php similarity index 96% rename from phpBB/includes/cron_tasks/standard/queue.php rename to phpBB/includes/cron/tasks/core/queue.php index 6a69799ef4..d7dfeb9319 100644 --- a/phpBB/includes/cron_tasks/standard/queue.php +++ b/phpBB/includes/cron/tasks/core/queue.php @@ -21,7 +21,7 @@ if (!defined('IN_PHPBB')) * * @package phpBB3 */ -class queue_cron_task extends cron_task_base +class cron_task_core_queue extends cron_task_base { /** * Runs this cron task. diff --git a/phpBB/includes/cron_tasks/standard/tidy_cache.php b/phpBB/includes/cron/tasks/core/tidy_cache.php similarity index 93% rename from phpBB/includes/cron_tasks/standard/tidy_cache.php rename to phpBB/includes/cron/tasks/core/tidy_cache.php index 7c47be06c1..69038a8a5a 100644 --- a/phpBB/includes/cron_tasks/standard/tidy_cache.php +++ b/phpBB/includes/cron/tasks/core/tidy_cache.php @@ -21,7 +21,7 @@ if (!defined('IN_PHPBB')) * * @package phpBB3 */ -class tidy_cache_cron_task extends cron_task_base +class cron_task_core_tidy_cache extends cron_task_base { /** * Runs this cron task. diff --git a/phpBB/includes/cron_tasks/standard/tidy_database.php b/phpBB/includes/cron/tasks/core/tidy_database.php similarity index 92% rename from phpBB/includes/cron_tasks/standard/tidy_database.php rename to phpBB/includes/cron/tasks/core/tidy_database.php index 16a17b3538..c6c2a60445 100644 --- a/phpBB/includes/cron_tasks/standard/tidy_database.php +++ b/phpBB/includes/cron/tasks/core/tidy_database.php @@ -21,7 +21,7 @@ if (!defined('IN_PHPBB')) * * @package phpBB3 */ -class tidy_database_cron_task extends cron_task_base +class cron_task_core_tidy_database extends cron_task_base { /** * Runs this cron task. diff --git a/phpBB/includes/cron_tasks/standard/tidy_search.php b/phpBB/includes/cron/tasks/core/tidy_search.php similarity index 96% rename from phpBB/includes/cron_tasks/standard/tidy_search.php rename to phpBB/includes/cron/tasks/core/tidy_search.php index ac42c26689..0f409d114a 100644 --- a/phpBB/includes/cron_tasks/standard/tidy_search.php +++ b/phpBB/includes/cron/tasks/core/tidy_search.php @@ -23,7 +23,7 @@ if (!defined('IN_PHPBB')) * * @package phpBB3 */ -class tidy_sessions_cron_task extends cron_task_base +class cron_task_core_tidy_sessions extends cron_task_base { /** * Runs this cron task. diff --git a/phpBB/includes/cron_tasks/standard/tidy_sessions.php b/phpBB/includes/cron/tasks/core/tidy_sessions.php similarity index 91% rename from phpBB/includes/cron_tasks/standard/tidy_sessions.php rename to phpBB/includes/cron/tasks/core/tidy_sessions.php index 6ff2dee14b..ea6aa70699 100644 --- a/phpBB/includes/cron_tasks/standard/tidy_sessions.php +++ b/phpBB/includes/cron/tasks/core/tidy_sessions.php @@ -21,7 +21,7 @@ if (!defined('IN_PHPBB')) * * @package phpBB3 */ -class tidy_sessions_cron_task extends cron_task_base +class cron_task_core_tidy_sessions extends cron_task_base { /** * Runs this cron task. diff --git a/phpBB/includes/cron_tasks/standard/tidy_warnings.php b/phpBB/includes/cron/tasks/core/tidy_warnings.php similarity index 94% rename from phpBB/includes/cron_tasks/standard/tidy_warnings.php rename to phpBB/includes/cron/tasks/core/tidy_warnings.php index 059125b18d..c1ab14d788 100644 --- a/phpBB/includes/cron_tasks/standard/tidy_warnings.php +++ b/phpBB/includes/cron/tasks/core/tidy_warnings.php @@ -23,7 +23,7 @@ if (!defined('IN_PHPBB')) * * @package phpBB3 */ -class tidy_warnings_cron_task extends cron_task_base +class cron_task_core_tidy_warnings extends cron_task_base { /** * Runs this cron task. diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index eb787bfc62..418e8dc51d 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -4617,11 +4617,12 @@ function page_footer($run_cron = true) if ($call_cron) { global $cron; - $cron_type = $cron->find_one_runnable_task(); + $task = $cron->find_one_ready_task(); - if ($cron_type) + if ($task) { - $template->assign_var('RUN_CRON_TASK', $cron->generate_task_code($cron_type)); + $url = $task->get_url(); + $template->assign_var('RUN_CRON_TASK', 'cron'); } } diff --git a/phpBB/viewforum.php b/phpBB/viewforum.php index 8a06e28394..a3fd9fa6fb 100644 --- a/phpBB/viewforum.php +++ b/phpBB/viewforum.php @@ -193,9 +193,13 @@ if ($forum_data['forum_topics_per_page']) } // Do the forum Prune thang - cron type job ... -if (!$config['use_system_cron'] && $cron->is_task_runnable('prune_forum', array($forum_data))) +if (!$config['use_system_cron']) { - $template->assign_var('RUN_CRON_TASK', $cron->generate_task_code('prune_forum', array($forum_id))); + $task = $cron->instantiate_task('core_prune_forum', $forum_data); + if ($task && $task->is_ready()) { + $url = $task->get_url(); + $template->assign_var('RUN_CRON_TASK', 'cron'); + } } // Forum rules and subscription info