Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 73 additions & 14 deletions docs/advanced-usage.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
# Advanced Usage

This guide covers the advanced features of Shepherd for more complex use cases.
Advanced Shepherd features for complex use cases.

## Automatic Retries

Shepherd can automatically retry failed tasks. A task is considered failed when it throws any exception during the `process()` method.
Shepherd automatically retries failed tasks (tasks that throw exceptions during `process()`).

### Configuring Retries

Override the `get_max_retries()` method on your task class. The default is `0` (no retries).
Override `get_max_retries()` in your task class. Default is `0` (no retries).

**Important**: This method returns the number of _additional_ attempts, not the total attempts. A task with 2 retries will execute up to 3 times total.
**Important**: Returns additional attempts, not total. A task with 2 retries executes up to 3 times total.

```php
<?php
Expand Down Expand Up @@ -40,7 +40,7 @@ class My_Retryable_Task extends Task_Abstract {

### Retry Delays

By default, Shepherd uses exponential backoff for retries. You can customize this by overriding `get_retry_delay()`:
Default uses exponential backoff. Customize by overriding `get_retry_delay()`:

```php
public function get_retry_delay(): int {
Expand Down Expand Up @@ -88,23 +88,22 @@ Groups help with:

## Unique Tasks

Shepherd prevents duplicate tasks from being scheduled. A task is considered a duplicate if it has the same class and arguments as an existing scheduled task.
Shepherd prevents duplicate tasks (same class and arguments) from being scheduled.

When you try to dispatch a duplicate task, Shepherd will:
When dispatching a duplicate task:

- Check if an identical task already exists (same class + arguments)
- If it exists, silently ignore the dispatch request. You can listen to an action to be notified when this happens. See [API Reference](api-reference.md) for more information.
- If it doesn't exist, schedule the task normally
- Identical task exists: Silently ignored (listen to action for notification - see [API Reference](api-reference.md))
- No identical task: Scheduled normally

This behavior prevents accidental task duplication and is enabled by default for all tasks.
Prevents accidental duplication and is enabled by default.

## Logging

Shepherd includes comprehensive logging that tracks the complete lifecycle of each task.
Comprehensive logging tracks the complete task lifecycle.

### Built-in Logging

By default, logs are stored in Action Scheduler's `actionscheduler_logs` table using the `ActionScheduler_DB_Logger`. This reduces database overhead by reusing existing infrastructure. The following events are automatically logged:
Default logs are stored in Action Scheduler's `actionscheduler_logs` table using `ActionScheduler_DB_Logger`. Reduces database overhead by reusing existing infrastructure. Automatically logged events:

- `created`: Task scheduled (triggers `shepherd_{prefix}_task_created` action)
- `started`: Task execution begins (triggers `shepherd_{prefix}_task_started` action)
Expand Down Expand Up @@ -223,17 +222,77 @@ protected function validate_args( ...$args ): void {
}
```

## Database Cleanup

Shepherd includes automatic database cleanup to maintain data integrity and prevent orphaned records.

### Automatic Cleanup on Action Deletion

When Action Scheduler deletes actions (through cleanup, manual deletion, or other processes), Shepherd automatically removes the corresponding task data to prevent orphaned records.

**How it works:**

1. **Hook Registration**: The `action_scheduler_deleted_action` hook is registered during Shepherd initialization
2. **Automatic Cleanup**: When an action is deleted, Shepherd queries for associated tasks
3. **Cascade Deletion**: Both task records and their logs are removed from Shepherd's tables
4. **Data Integrity**: Prevents accumulation of orphaned data

**Example behavior:**

```php
// When Action Scheduler deletes an action with ID 123
do_action( 'action_scheduler_deleted_action', 123 );

// Shepherd automatically:
// 1. Finds tasks with action_id = 123
// 2. Deletes associated logs from shepherd_task_logs
// 3. Deletes task records from shepherd_tasks
// No manual intervention required
```

### Periodic Cleanup with Herding Task

The [Herding task](tasks/herding.md) runs every 6 hours to clean up any orphaned data that might exist due to:

- Database corruption
- External modifications to Action Scheduler tables
- Race conditions during cleanup

**Combined Strategy:**

- **Immediate cleanup**: Action deletion hook removes data when actions are deleted
- **Periodic cleanup**: Herding task catches any missed orphaned data
- **Database integrity**: Ensures consistent state between Shepherd and Action Scheduler

### Manual Cleanup

If you need to manually clean up orphaned data:

```php
// Run the Herding task immediately
shepherd()->dispatch( new \StellarWP\Shepherd\Tasks\Herding() );

// Or trigger Action Scheduler cleanup
as_unschedule_all_actions( 'shepherd_task_prefix' );
```

## Performance Considerations

### Database Optimization

The task tables include indexes on:

- `action_id`: For Action Scheduler integration
- `action_id`: For Action Scheduler integration and cleanup operations
- `args_hash`: For duplicate detection
- `class_hash`: For task type queries
- `task_id`: For log retrieval

### Cleanup Performance

- **Batch Operations**: Cleanup operations use batch deletions for efficiency
- **Indexed Queries**: All cleanup queries use indexed columns for optimal performance
- **Minimal Overhead**: Action deletion hooks add minimal overhead to Action Scheduler operations

## Advanced Integration

### WordPress Hooks
Expand Down
13 changes: 13 additions & 0 deletions docs/api-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,19 @@ Returns the container instance.

Checks if Shepherd has been registered.

##### `delete_tasks_on_action_deletion( int $action_id ): void`

Automatically removes task data when Action Scheduler deletes an action.

- **Parameters:**
- `$action_id` - The Action Scheduler action ID being deleted
- **Behavior:**
- Queries for tasks associated with the action ID
- Removes corresponding logs from `shepherd_task_logs`
- Removes task records from `shepherd_tasks`
- No-op if no tasks are associated with the action ID
- **Hook:** Automatically called on `action_scheduler_deleted_action`

---

### `Email` Task
Expand Down
36 changes: 16 additions & 20 deletions docs/getting-started.md
Original file line number Diff line number Diff line change
@@ -1,26 +1,24 @@
# Getting Started with Shepherd

This guide will walk you through the basics of installing and using Shepherd to run your first background task.
Install and use Shepherd to run your first background task.

## Installation

Shepherd is a Composer package that provides a robust background task processing system for WordPress applications. To install it, you'll need to have Composer in your project. If you don't have it already, you can follow the instructions on the [Composer website](https://getcomposer.org/).

Once you have Composer set up, you can add Shepherd to your project by running the following command in your project's root directory:
Require Shepherd as a production dependency via Composer:

```bash
composer require stellarwp/shepherd
```

After installing Shepherd, you need to make sure you're including the Composer autoloader in your plugin or theme. This is typically done by adding the following line to your main plugin file or `functions.php`:
Include the Composer autoloader in your plugin or theme:

```php
require_once __DIR__ . '/vendor/autoload.php';
```

## Configuration and Registration

Shepherd requires a DI container that implements `StellarWP\ContainerContract\ContainerInterface`. You need to configure and register Shepherd before using it. This is typically done in your plugin's main file:
Shepherd requires a DI container implementing `StellarWP\ContainerContract\ContainerInterface`. Register Shepherd in your plugin:

```php
use StellarWP\Shepherd\Config;
Expand Down Expand Up @@ -53,7 +51,7 @@ add_action( 'plugins_loaded', function() {

### Configuration Options

Before registering Shepherd, you can configure it using the `Config` class:
Configure Shepherd before registration:

```php
// Set a custom logger (optional - defaults to DB_Logger)
Expand All @@ -65,9 +63,7 @@ $prefix = Config::get_hook_prefix();

## Creating Your First Task

Tasks in Shepherd are classes that extend the `StellarWP\Shepherd\Abstracts\Task_Abstract` class. At a minimum, you need to implement the `process()` method and `get_task_prefix()` method.

Let's create a simple task that logs a message:
Tasks extend `Task_Abstract` and implement `process()` and `get_task_prefix()` methods:

```php
<?php
Expand Down Expand Up @@ -124,7 +120,7 @@ class Log_Message_Task extends Task_Abstract {

## Dispatching Your Task

Once you've created your task, you can dispatch it using the `shepherd()` helper function:
Dispatch tasks using the `shepherd()` helper:

```php
use My\App\Tasks\Log_Message_Task;
Expand All @@ -143,16 +139,16 @@ shepherd()->dispatch( $my_task, 5 * MINUTE_IN_SECONDS ); // Execute after 5 minu
### What Happens Next?

1. Shepherd schedules your task with Action Scheduler
2. WordPress cron (or another Action Scheduler's runner, like CLI) picks up the task
3. Your task's `process()` method is executed
4. The task lifecycle is logged in the database
5. If the task fails, it may be retried based on your configuration
2. WordPress cron picks up the task
3. Your task's `process()` method executes
4. The lifecycle is logged in the database
5. Failed tasks may be retried based on configuration

Check your `debug.log` file, and you should see the message "Shepherd Task: Hello, World! with code 200".
Check `debug.log` for the message "Shepherd Task: Hello, World! with code 200".

## Verifying Task Execution

You can check if your task was scheduled successfully:
Check if your task was scheduled successfully:

```php
// Get the last scheduled task ID
Expand All @@ -168,9 +164,9 @@ $logs = $logger->retrieve_logs( $task_id );

## Next Steps

- Learn about [Advanced Usage](./advanced-usage.md) including retries, debouncing, and custom configuration
- Explore the [Built-in Tasks](./tasks.md) that come with Shepherd
- Read the [API Reference](./api-reference.md) for detailed information about all classes and methods
- [Advanced Usage](./advanced-usage.md) - retries, debouncing, custom configuration
- [Built-in Tasks](./tasks.md) - tasks included with Shepherd
- [API Reference](./api-reference.md) - detailed class and method documentation

## Troubleshooting

Expand Down
60 changes: 44 additions & 16 deletions docs/tasks.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Built-in Tasks

Shepherd comes with pre-packaged tasks to handle common background operations. Each task is designed to be reliable, well-tested, and includes automatic retry logic.
Shepherd includes reliable, well-tested tasks for common background operations with automatic retry logic.

## Available Tasks

Expand Down Expand Up @@ -32,7 +32,7 @@ shepherd()->dispatch( $email );

### [HTTP Request Task](./tasks/http-request.md)

Makes HTTP requests asynchronously using WordPress's `wp_remote_request()` function.
Makes asynchronous HTTP requests using WordPress's `wp_remote_request()`.

**Key Features:**

Expand Down Expand Up @@ -74,9 +74,40 @@ class Authenticated_HTTP_Request extends HTTP_Request {
}
```

## Creating Your Own Tasks
### [Herding Task](./tasks/herding.md)

To create custom tasks, extend the `Task_Abstract` class:
Automatically cleans up orphaned task data to maintain database integrity.

**Key Features:**

- Automatic scheduling (every 6 hours)
- Removes orphaned task records and logs
- Safe database operations with prepared statements
- Completion hooks for extensibility
- No-op when no cleanup needed

**Automatic Usage:**

```php
// Runs automatically every 6 hours - no manual intervention needed
// Attached to WordPress 'init' hook with priority 20
```

**Manual Usage:**

```php
use StellarWP\Shepherd\Tasks\Herding;

// Dispatch immediately for manual cleanup
shepherd()->dispatch( new Herding() );

// Or schedule for later
shepherd()->dispatch( new Herding(), HOUR_IN_SECONDS );
```

## Creating Custom Tasks

Extend `Task_Abstract` for custom tasks:

```php
<?php
Expand Down Expand Up @@ -113,11 +144,11 @@ class My_Custom_Task extends Task_Abstract {

## Task Design Principles

When creating tasks, follow these principles:
Follow these principles when creating tasks:

### 1. Idempotent Operations

A Task's `process()` method should be safe to run multiple times with different arguments:
Tasks should be safe to run multiple times:

### 2. Clear Error Handling

Expand Down Expand Up @@ -156,14 +187,11 @@ class Process_Everything extends Task_Abstract {
}
```

Instead of doing everything in one task, you can create multiple tasks that are more focused and easier to test. On each task's `process()` method, you can fire an `action` than next tasks can listen to, or directly schedule the next task to be processed via `shepherd()->dispatch()`.
Create multiple focused tasks instead. Chain tasks by firing actions or directly scheduling via `shepherd()->dispatch()`.

### 4. Proper Argument Validation

Validate inputs by:

1. Calling the parent constructor.
2. Overriding the `validate_args()` method.
Validate inputs by calling the parent constructor and overriding `validate_args()`:

```php
public function __construct( string $email, int $user_id ) {
Expand All @@ -183,12 +211,12 @@ protected function validate_args(): void {

## Contributing Tasks

If you've created a useful task that could benefit others, consider contributing it to the Shepherd library:
To contribute useful tasks to Shepherd:

1. Ensure your task follows WordPress coding standards
1. Follow WordPress coding standards
2. Include comprehensive PHPDoc comments
3. Add integration tests for your task in the `tests/integration/Tasks/` directory
4. Update documentation in the `docs/` directory
3. Add integration tests in `tests/integration/Tasks/`
4. Update documentation in `docs/`
5. Submit a pull request

## Future Built-in Tasks
Expand All @@ -200,4 +228,4 @@ Planned tasks for future releases:
- **Cache Warming Task**: Pre-populate caches
- **Bulk Operations Task**: Handle large data sets in chunks

Have ideas for built-in tasks? [Open an issue](https://github.com/stellarwp/shepherd/issues) to discuss your suggestions.
Have ideas? [Open an issue](https://github.com/stellarwp/shepherd/issues) to discuss suggestions.
Loading
Loading