# Action Scheduler Job Framework
## Requirements
- PHP 7.0+
- [Jetpack Autoloader](https://github.com/Automattic/jetpack-autoloader) - Required to ensure the latest version of the framework is used in case multiple plugins have it as a dependency
## Versioning & breaking changes
This package follows [Semver](https://semver.org/) for versioning.
This framework may receive breaking changes at the moment while it is only used in the [Facebook for WooCommerce](https://github.com/woocommerce/facebook-for-woocommerce) plugin.
However, once we use it in another plugin we will need to reject all breaking changes.
## Installation
The framework should be installed via [Composer](https://getcomposer.org/).
1. Add the following to your project's `composer.json` file:
```json
{
"repositories": [
{
"type": "vcs",
"url": "https://github.com/woocommerce/action-scheduler-job-framework"
}
],
"require": {
"woocommerce/action-scheduler-job-framework": "1.0.0"
}
}
```
2. Then run `composer update`
## Chained Jobs
A "chained job" is a kind of batched job that creates follow-up actions in a chain until a set of items has been processed.
Each "batch" in the job is a separate "scheduled action". Each batch is numbered and should be limited to process a set number of items.
### Methods
- `::handle_start()` - Runs before a job instance starts.
- `::handle_end()` - Runs after a job instance ends.
- `::get_items_for_batch()` - Gets a set of items for the batch to process.
- `::process_item()` - Processes a single item.
- `::get_name()` - Get the unique name/ID of the job.
- `::get_number_of_items_processed()` - Get the number of items that have been processed by the currently running instance of the job.
- `::is_running()` - Check if this job is currently running. Checks if there is any "start" or "batch" actions `pending` or `in-progress` for the job.
### Example:
```php
class GenerateProductFeed extends Automattic\WooCommerce\ActionSchedulerJobFramework\AbstractChainedJob {
use Automattic\WooCommerce\ActionSchedulerJobFramework\Utilities\BatchQueryOffset;
/**
* Runs before starting the job.
*/
protected function handle_start() {
// Optionally do something when starting the job.
}
/**
* Runs after the finishing the job.
*/
protected function handle_end() {
// Optionally do something when ending the job.
}
/**
* Get a set of items for the batch.
*
* NOTE: when using an OFFSET based query to retrieve items it's recommended to order by the item ID while
* ASCENDING. This is so that any newly added items will not disrupt the query offset.
*
* @param int $batch_number The batch number increments for each new batch in the job cycle.
* @param array $args The args for the job.
*
* @throws Exception On error. The failure will be logged by Action Scheduler and the job chain will stop.
*/
protected function get_items_for_batch( int $batch_number, array $args ): array {
$product_args = [
'fields' => 'ids',
'post_status' => 'publish',
'post_type' => [ 'product', 'product_variation' ],
'posts_per_page' => $this->get_batch_size(),
'offset' => $this->get_query_offset( $batch_number ),
'orderby' => 'ID',
'order' => 'ASC',
];
$query = new WP_Query( $product_args );
return $query->posts;
}
/**
* Process a single item.
*
* @param string|int|array $item A single item from the get_items_for_batch() method.
* @param array $args The args for the job.
*
* @throws Exception On error. The failure will be logged by Action Scheduler and the job chain will stop.
*/
protected function process_item( $item, array $args ) {
// Process each item here.
}
/**
* Get the name/slug of the job.
*
* @return string
*/
public function get_name(): string {
return 'generate_feed';
}
/**
* Get the name/slug of the plugin that owns the job.
*
* @return string
*/
public function get_plugin_name(): string {
return 'facebook_for_woocommerce';
}
}
add_action( 'init', function() {
$job = new GenerateProductFeed(
new \Automattic\WooCommerce\ActionSchedulerJobFramework\Proxies\ActionScheduler()
);
$job->init();
// Start the job if it's not already running
if ( ! $job->is_running() ) {
$job->queue_start();
}
});
```