Giter VIP home page Giter VIP logo

wp-module-tasks's Introduction

Newfold Logo

WordPress Tasks Module

A task system for processing asynchronous tasks with wordpress, the tasks could be one-off long running tasks or periodic tasks.

Module Responsibilities

  • Define structures for both one-off and periodic tasks, including necessary parameters such as priority and task type.
  • Maintain a queue of pending tasks in database.
  • Provide interfaces for adding, updating, and removing tasks.
  • Handle task prioritization to ensure that tasks are executed in the order of their priority.
  • Implement scheduling mechanisms for both one-off and periodic tasks, ensuring timely execution according to predefined schedules.
  • Execute one-off and periodic tasks asynchronously in the background, allowing the system to continue processing tasks without blocking.
  • Remove completed tasks from the system after execution to maintain efficiency and prevent unnecessary resource usage.

Critical Paths

  • When a one-off or periodic task is scheduled, the scheduler component is responsible for picking up tasks based on their priority.
  • The scheduler initiates the execution of tasks, ensuring that they are processed in the correct order.
  • If a task fails during execution, the scheduler handles retries according to predefined policies, ensuring that tasks are eventually completed successfully.

Installation

1. Add the Newfold Satis to your composer.json.

composer config repositories.newfold composer https://newfold-labs.github.io/satis

2. Require the newfold-labs/wp-module-tasks package.

composer require newfold-labs/wp-module-tasks

More on NewFold WordPress Modules

Tasks

The system intends to support one-off and periodic tasks.
One-off tasks will be the long running tasks which will be executed by the system in background in an asynchronous manner, these tasks will be picked up according to the priority assigned to them, results will be recorded and then the tasks will subsequently be removed from the system, i.e. we will not be tracking these tasks again unless they are inserted back with other parameters. Some examples of tasks like these could be packaging wordpress related items, sending emails, installing a plugin, updating a plugin, bulk installs, bulk updates etc.

Setting up the module

In order for the module to work, we'd need tables for storing the tasks queue and the task results, please use the following functions in order to automatically create / delete the tables while activating and deactivating the plugin.

register_activation_hook( __FILE__, 'nfd_tasks_setup_tables' );
register_deactivation_hook( __FILE__, 'nfd_tasks_purge_tables' );

Adding a one-off task.

After you include the module as a dependency in your plugin, you can then schedule a one-off task for a function foo to be run as below:

use NewfoldLabs\WP\Module\Tasks\Models\Task;

function foo( $args ) {
    // do something.
}
$task = new Task();
// or use any loaded function like \Class::static_func etc.
$task->set_task_name('hello')
    ->set_task_execute('foo')
    ->set_num_retries(2)
    ->set_args( $args )
    ->set_priority( 10 );
// Queue the task by
$task->queue_task();

The scheduler will take up tasks based on the task priority and take care of retries in case the task fails. The scheduler will also be responsible for recording the results for the task runs in a db called wp_task_results.

Adding a periodic task.

The installation and including of the module works the same as in the case of one-off tasks, we can add periodic tasks very similar to how we add a one-off task, only difference is in the parameters we pass while creating that module like so:

use NewfoldLabs\WP\Module\Tasks\Models\Task;

function foo( $args ) {
    // do something.
}

$task = new Task();
$task->set_name('foo_task')
    ->set_task_execute('foo')
    ->set_args( $args )
    ->set_interval(30)
$task->queue_task();

Caveats

You can not be sure of the time when the one-off tasks will execute, since the system depends on wp-cron and which in turn depends on page loads, the tasks will not run unless there are enough page loads.

PS: It is possible to simulate page loads with a request to /wp-cron.php, and hook this request with an actual cron to ensure that the tasks keep running when required

Refer: https://developer.wordpress.org/plugins/cron/hooking-wp-cron-into-the-system-task-scheduler/ for more.

wp-module-tasks's People

Contributors

amartya-dev avatar girish-lokapure avatar wpscholar avatar

Stargazers

 avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

wp-module-tasks's Issues

Implement tests

We should implement some PHPUnit tests for key functionality.

Reconsider method of Task instantiation

Having 9 parameters to instantiate a Task seems a bit much. Do we really need them all in the constructor?

$id = null,
$task_name = null,
$task_executor_path = null,
$task_execute = null,
$args = null,
$num_retries = 0,
$task_interval = null,
$task_priority = null,
$enabled = true

For example, why not default to a low or mid-range priority and then allow calling $task->priority( 80 ) to change it?

By introducing chainable methods, we could do something like $task->priority( 80 )->retries(3). This allows us to instantiate in a more reader-friendly way and without having to pass null for multiple parameters.

Update Satis reference in readme file

Update readme Satis reference:

composer config repositories.newfold composer https://newfold.github.io/satis

Should be:

composer config repositories.newfold composer https://newfold-labs.github.io/satis

What are the use cases for disabling a task?

Is there a reason we would disable a task as opposed to just deleting it?

If not, we should remove the enabled column from the database as well as any class properties, etc.

Restrict when tables checks are done and add code to allow deleting tables as well

Currently, table setup checks are being run on every page load. We should change that up so that the plugin can call a function in the module when the plugin is activated (or deactivated) to set up or remove those tables. Alternatively, our plugins have upgrade routines that could handle the table setup.

public static function setup() {
global $wpdb;
$table_name = MODULE_TASKS_TASK_TABLE_NAME;
// Maybe create the table
if ( ! function_exists( 'maybe_create_table' ) ) {
require_once ABSPATH . 'wp-admin/includes/upgrade.php';
}
$charset_collate = $wpdb->get_charset_collate();
$sql = "CREATE TABLE `{$wpdb->prefix}{$table_name}` (
task_id bigint(20) NOT NULL AUTO_INCREMENT,
task_name varchar(63) NOT NULL,
task_executor_path varchar(125),
task_execute varchar(125),
args longtext,
num_retries int(2) UNSIGNED,
task_interval int(2) UNSIGNED,
task_priority int(2) UNSIGNED,
task_status varchar(12),
updated TIMESTAMP NOT NULL ON UPDATE CURRENT_TIMESTAMP,
enabled tinyint(1),
PRIMARY KEY (task_id)
) $charset_collate;";
maybe_create_table( $wpdb->prefix . $table_name, $sql );
}

public static function setup() {
global $wpdb;
$table_name = MODULE_TASKS_TASK_RESULTS_TABLE_NAME;
// Maybe create the table
if ( ! function_exists( 'maybe_create_table' ) ) {
require_once ABSPATH . 'wp-admin/includes/upgrade.php';
}
$charset_collate = $wpdb->get_charset_collate();
$sql = "CREATE TABLE `{$wpdb->prefix}{$table_name}` (
task_result_id bigint(20) NOT NULL AUTO_INCREMENT,
task_id bigint(20) NOT NULL,
task_name varchar(63) NOT NULL,
stacktrace longtext,
success tinyint(1),
updated TIMESTAMP NOT NULL ON UPDATE CURRENT_TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (task_result_id)
) $charset_collate;";
maybe_create_table( $wpdb->prefix . $table_name, $sql );
}

Use `set_time_limit()` instead of `ini_set( 'max_execution_time' )`

As a best practice, we should use the set_time_limit() function instead of the ini_set() function and setting max_execution_time.

The primary reason is that the set_time_limit() function sets the time limit for the current script only. Setting max_execution_time impacts the entire PHP environment and could cause performance issues.

Make cron schedule configurable

Having a 20-second cron schedule could overwhelm the site’s resources with overlapping cron tasks on a high-traffic site.

While I realize this 20-second cron is important when setting up a site to ensure plugins are properly installed during onboarding, I don't think we should retain this cron schedule past onboarding.

/**
* Add a 20 seconds interval
*
* @param array $schedules The existing interval schedules
*/
public function add_interval_schedule( $schedules ) {
// Adds the schedule for the given intervals in seconds
if ( ! array_key_exists( 'twenty_seconds', $schedules ) || 20 !== $schedules[ 'twenty_seconds' ]['interval'] ) {
$schedules[ 'twenty_seconds' ] = array(
'interval' => 20,
'display' => __( 'Cron to run once every twenty seconds' ),
);
}
// Adds the schedule for the given intervals in seconds
if ( ! array_key_exists( 'ten_minutes', $schedules ) || 600 !== $schedules[ 'ten_minutes' ]['interval'] ) {
$schedules[ 'ten_minutes' ] = array(
'interval' => 600,
'display' => __( 'Cron to run once every ten minutes' ),
);
}
return $schedules;
}

The existing cleanup task should happen on the pre-existing 15-minute cron instead of adding a new 10-minute cron.

We should remove the 20-second cron and make it possible to configure custom cron schedules to handle different groups/types of tasks at different intervals.

Avoid use of `phpcs:ignore`

We should avoid using // phpcs:ignore since this ignores ALL rules. I think it is probably irrelevant in most cases since you've addressed the issues. However, if there is a specific rule we are trying to intentionally ignore, we should include the rule name in the comment so that other rules aren't ignored.

Instances:

Consider making priority optional

It seems like there would be times when just ordering tasks by priority alone could be limiting. It seems like we might want to have some tasks processed based on date/time, with priority being optional or being an additional sort if priority is the same.

I can see not using priority at all for handling things like processing admin page view events and instead handling those as either a stack (LIFO) or a queue (FIFO).

There could be other times when we would want a true queue or stack instead of a solely priority-based system.

I'd love to see a system where you can instantiate a queue, and configure it to run one or more jobs on a subset of tasks (e.g. by task name) at a specific cron interval. Likewise, you could instantiate a stack or priority queue at different intervals for different subsets of tasks.

I think this package would provide some inspiration in this direction: https://github.com/deliciousbrains/wp-queue

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.