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
36 changes: 36 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,42 @@ All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog and adheres to Semantic Versioning.


## [2.0.0] - 2025-10-13
### Breaking Changes
- **Plugin renamed**: "Redis Queue Demo" → "Redis Queue"
- **Namespace changed**: `Soderlind\RedisQueueDemo` → `Soderlind\RedisQueue` across all classes
- **Function names changed**: `redis_queue_demo_*()` → `redis_queue_*()`
- **Filter/action names changed**: `redis_queue_demo_*` → `redis_queue_*`
- **Text domain changed**: `redis-queue-demo` → `redis-queue`
- **GitHub repository**: URLs updated from `redis-queue-demo` to `redis-queue`
- **Composer package**: Will be `soderlind/redis-queue` (currently `soderlind/redis-queue-demo`)
- **Download file name**: Changed from `redis-queue-demo.zip` to `redis-queue.zip`
- **No backward compatibility**: Legacy class aliases and function names have been completely removed

### Migration Guide
To migrate from 1.x to 2.0.0:

1. **Update namespace imports**:
- Old: `use Soderlind\RedisQueueDemo\Core\Redis_Queue_Manager;`
- New: `use Soderlind\RedisQueue\Core\Redis_Queue_Manager;`

2. **Update function calls**:
- Old: `redis_queue_demo()`
- New: `redis_queue()`
- Old: `redis_queue_demo_create_job` filter
- New: `redis_queue_create_job` filter

3. **Update action/filter hooks**:
- Old: `add_filter('redis_queue_demo_token_allowed_routes', ...)`
- New: `add_filter('redis_queue_token_allowed_routes', ...)`

4. **Update options migration**: A one-time migration automatically renames options from `redis_queue_demo_*` to `redis_queue_*` on first activation of 2.0.0.

### Changed
- Complete documentation overhaul to reflect new plugin name and namespace
- All code examples updated to use new function and filter names
- REST API namespace remains `redis-queue/v1` for API stability

## [1.2.0] - 2025-10-10
### Removed
- Dropped all legacy global class aliases (previous `class_alias` guards) now that backward compatibility is not required.
Expand Down
77 changes: 11 additions & 66 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Redis Queue Demo for WordPress
# Redis Queue for WordPress

Robust Redis-backed background job processing for WordPress. Provides prioritized, delayed, and retryable jobs with an admin UI, REST API, token-based auth (scopes + rate limiting), and extensibility for custom job types.

The idea is to give inspiration to build production-ready queue systems in WordPress, following best practices and patterns.
A production-ready queue system for WordPress, following best practices and patterns.

## Feature Highlights

Expand Down Expand Up @@ -128,14 +128,14 @@ composer require predis/predis

- **Quick Install**

- Download [`redis-queue-demo.zip`](https://github.com/soderlind/redis-queue-demo/releases/latest/download/redis-queue-demo.zip)
- Download [`redis-queue.zip`](https://github.com/soderlind/redis-queue/releases/latest/download/redis-queue.zip)
- Upload via Plugins > Add New > Upload Plugin
- Activate the plugin.

- **Composer Install**

```bash
composer require soderlind/redis-queue-demo
composer require soderlind/redis-queue
```

- **Updates**
Expand Down Expand Up @@ -218,7 +218,7 @@ Data: {"test": "message"}
5. Run workers manually (admin button) or on a schedule (cron / wp-cli / external runner).

```bash
git clone https://github.com/soderlind/redis-queue-demo.git wp-content/plugins/redis-queue-demo
git clone https://github.com/soderlind/redis-queue.git wp-content/plugins/redis-queue
```

Optionally add Predis:
Expand All @@ -235,13 +235,15 @@ define( 'REDIS_QUEUE_DATABASE', 0 );

Then enqueue a job programmatically:
```php
use Soderlind\RedisQueue\Jobs\Email_Job;

$job = new Email_Job([
'email_type' => 'single',
'to' => 'admin@example.com',
'subject' => 'Hello',
'message' => 'Testing queue'
]);
redis_queue_demo()->queue_manager->enqueue( $job );
redis_queue()->queue_manager->enqueue( $job );
```

Process jobs:
Expand Down Expand Up @@ -285,14 +287,14 @@ Full details: see the [REST API documentation](docs/worker-rest-api.md).

## Extending

Implement a subclass of `Abstract_Base_Job`, override `get_job_type()` + `execute()`, optionally `should_retry()` and `handle_failure()`. Register dynamically with the `redis_queue_demo_create_job` filter. Full guide: [Extending Jobs](docs/extending-jobs.md).
Implement a subclass of `Abstract_Base_Job`, override `get_job_type()` + `execute()`, optionally `should_retry()` and `handle_failure()`. Register dynamically with the `redis_queue_create_job` filter. Full guide: [Extending Jobs](docs/extending-jobs.md).

## Scheduling Workers

Examples:
```bash
# Cron (every minute)
* * * * * wp eval "redis_queue_demo()->process_jobs();"
* * * * * wp eval "redis_queue()->process_jobs();"
```
For higher throughput run multiple workers targeting distinct queues.

Expand All @@ -317,61 +319,4 @@ Made with ❤️ by [Per Søderlind](https://soderlind.no)

---

For detailed usage, advanced features, troubleshooting, and performance tuning visit the [Usage guide](docs/usage.md). Additional topics: [Scaling](docs/scaling.md), [Maintenance](docs/maintenance.md).

## Namespacing & Backward Compatibility (Refactor Notes)

As of the latest refactor, all core classes have been migrated to the `Soderlind\\RedisQueueDemo` namespace and autoloaded via Composer PSR-4. Legacy global class names (`Redis_Queue_Demo`, `Redis_Queue_Manager`, `Job_Processor`, `Sync_Worker`, `REST_Controller`, `Admin_Interface`, job classes, etc.) are still available through `class_alias` so existing integrations that referenced the old globals continue to work without modification.

Removed legacy duplicate files:
```
admin/class-admin-interface.php
api/class-rest-controller.php
workers/class-sync-worker.php
```
Their logic now lives in:
```
src/Admin/Admin_Interface.php
src/API/REST_Controller.php
src/Workers/Sync_Worker.php
```

Helper functions (`redis_queue_demo()`, `redis_queue_enqueue_job()`, `redis_queue_process_jobs()`) remain unchanged for ergonomics.

If you previously required or included specific legacy files manually, you should remove those `require` statements—Composer autoload now handles class loading.

### Migrating Custom Integrations

If you instantiated legacy classes directly, both of the following are now equivalent:
```php
$manager = new Redis_Queue_Manager(); // legacy global (still works)
$manager = new \Soderlind\RedisQueueDemo\Core\Redis_Queue_Manager(); // namespaced
```

Custom job classes should adopt the namespace pattern and be placed under `src/YourNamespace/` with an appropriate `composer.json` autoload mapping, or hooked via the `redis_queue_demo_create_job` filter returning a namespaced job instance.

### Why This Change?

1. Autoload performance & structure clarity.
2. Avoiding global symbol collisions.
3. Easier extension via modern PHP tooling.
4. Future unit test isolation.

If you encounter any missing class errors after upgrading, clear WordPress object/opcode caches and run:
```bash
composer dump-autoload -o
```

Please report any backward compatibility regressions in the issue tracker.

### Admin Interface Inlining (UI Unchanged)

The legacy `admin/class-admin-interface.php` file was fully inlined into the namespaced `src/Admin/Admin_Interface.php` to remove manual `require` calls. To preserve the exact markup/CSS hooks, the original page layouts were ported as partial templates under:
```
src/Admin/partials/
dashboard-inline.php
jobs-inline.php
test-inline.php
settings-inline.php
```
These are loaded internally by the namespaced class; you should not include them directly. If you previously overrode or filtered admin output, existing selectors and element structures remain stable.
For detailed usage, advanced features, troubleshooting, and performance tuning visit the [Usage guide](docs/usage.md). Additional topics: [Scaling](docs/scaling.md), [Maintenance](docs/maintenance.md).
2 changes: 1 addition & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Documentation Index

Central hub for Redis Queue Demo plugin documentation.
Central hub for Redis Queue plugin documentation.

## Guides

Expand Down
12 changes: 6 additions & 6 deletions docs/extending-jobs.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# Extending Jobs

This guide explains how to create custom background jobs by extending the base abstractions provided by Redis Queue Demo.
This guide explains how to create custom background jobs by extending the base abstractions provided by Redis Queue.

## Core Concepts

Important: The plugin now exclusively uses namespaced classes and only canonical job type identifiers you define (e.g. `email`, `image_processing`, `api_sync`, or your custom strings). Legacy/global class name variants (like `Email_Job`, `email_job`) are not auto-mapped.
Important: The plugin now exclusively uses namespaced classes under `Soderlind\RedisQueue` and only canonical job type identifiers you define (e.g. `email`, `image_processing`, `api_sync`, or your custom strings). Legacy/global class name variants are not supported.

A job represents a unit of work executed asynchronously by a worker. Each job class encapsulates:

Expand Down Expand Up @@ -78,7 +78,7 @@ $job->set_priority( 10 ); // optional
$job->set_queue_name( 'reports' ); // optional
$job->set_delay_until( time() + 600 ); // run in 10 minutes

$job_id = redis_queue_demo()->get_queue_manager()->enqueue( $job );
$job_id = redis_queue()->get_queue_manager()->enqueue( $job );
```

### Processing
Expand Down Expand Up @@ -144,10 +144,10 @@ public static function create_report( $report_id ) {

### Registering / Filtering Custom Types

If you want dynamic creation based on a string type (e.g., via REST), add a filter where the plugin instantiates jobs. For this plugin, extend `redis_queue_demo_create_job` filter (see `redis-queue-demo.php`):
If you want dynamic creation based on a string type (e.g., via REST), add a filter where the plugin instantiates jobs. For this plugin, extend `redis_queue_create_job` filter:

```php
add_filter( 'redis_queue_demo_create_job', function( $job, $job_type, $payload ) {
add_filter( 'redis_queue_create_job', function( $job, $job_type, $payload ) {
if ( $job ) { return $job; }
if ( 'report_generation' === $job_type ) {
return new Report_Generation_Job( $payload );
Expand Down Expand Up @@ -179,7 +179,7 @@ Internally the job is placed in a delayed sorted set until due.

- Use the admin “Full Debug Test” for baseline health.
- Inspect the job record in DB table `wp_redis_queue_jobs`.
- Check Redis keys with the configured prefix (`redis-cli KEYS "*redis_queue_demo*"`).
- Check Redis keys with the configured prefix (`redis-cli KEYS "*redis_queue*"`).
- Enable request logging & look at log lines for REST interactions.

### Best Practices
Expand Down
6 changes: 3 additions & 3 deletions docs/maintenance.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,15 @@ Request logging (if enabled) rotates by size:
Potential future cron to purge directly:
```php
// Sketch example
add_action( 'redis_queue_demo_maintenance', function() {
add_action( 'redis_queue_maintenance', function() {
global $wpdb; $t = $wpdb->prefix . 'redis_queue_jobs';
$wpdb->query( $wpdb->prepare("DELETE FROM $t WHERE status='completed' AND created_at < %s", gmdate('Y-m-d H:i:s', time()-7*DAY_IN_SECONDS) ) );
});
```
Schedule with:
```php
if ( ! wp_next_scheduled( 'redis_queue_demo_maintenance' ) ) {
wp_schedule_event( time()+300, 'hourly', 'redis_queue_demo_maintenance' );
if ( ! wp_next_scheduled( 'redis_queue_maintenance' ) ) {
wp_schedule_event( time()+300, 'hourly', 'redis_queue_maintenance' );
}
```

Expand Down
2 changes: 1 addition & 1 deletion docs/scaling.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Scaling Workers & Throughput

Guidance for scaling Redis Queue Demo beyond a single synchronous worker.
Guidance for scaling Redis Queue beyond a single synchronous worker.

## Objectives
- Increase parallel job throughput
Expand Down
14 changes: 7 additions & 7 deletions docs/usage.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Usage & Operations Guide

This document centralizes day-to-day usage, programmatic patterns, advanced features, troubleshooting, and performance practices for the Redis Queue Demo plugin.
This document centralizes day-to-day usage, programmatic patterns, advanced features, troubleshooting, and performance practices for the Redis Queue plugin.

## Table of Contents
1. Admin Interface
Expand Down Expand Up @@ -85,7 +85,7 @@ curl -X POST "https://yoursite.com/wp-json/redis-queue/v1/jobs" \

### Creating & Enqueuing Jobs
```php
use Soderlind\RedisQueueDemo\Jobs\Email_Job;
use Soderlind\RedisQueue\Jobs\Email_Job;

$email_job = new Email_Job([
'email_type' => 'single',
Expand All @@ -97,16 +97,16 @@ $email_job = new Email_Job([
$email_job->set_priority(10);
$email_job->set_queue_name('emails');

$job_id = redis_queue_demo()->get_queue_manager()->enqueue( $email_job );
$job_id = redis_queue()->get_queue_manager()->enqueue( $email_job );
```

### Processing Jobs Manually
```php
use Soderlind\RedisQueueDemo\Workers\Sync_Worker;
use Soderlind\RedisQueue\Workers\Sync_Worker;

$worker = new Sync_Worker(
redis_queue_demo()->get_queue_manager(),
redis_queue_demo()->get_job_processor()
redis_queue()->get_queue_manager(),
redis_queue()->get_job_processor()
);
$results = $worker->process_jobs( [ 'default', 'emails' ], 5 );
```
Expand Down Expand Up @@ -213,7 +213,7 @@ ini_set( 'max_execution_time', 300 );
### Worker Scheduling
Cron / supervisor strategies:
```
* * * * * wp eval "redis_queue_demo()->process_jobs();"
* * * * * wp eval "redis_queue()->process_jobs();"
```
Consider external runners for higher throughput.

Expand Down
22 changes: 11 additions & 11 deletions docs/worker-rest-api.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Redis Queue Demo – REST API Documentation
# Redis Queue – REST API Documentation

Base Namespace: `redis-queue/v1`
Base URL Example: `https://example.com/wp-json/redis-queue/v1/`
Expand Down Expand Up @@ -45,7 +45,7 @@ Notes:
- Nonce header is only required for cookie-based WP auth, not for token auth.
- Treat the token like a password. Regenerating on the settings page invalidates the old token.
- To revoke token access, clear the token on the settings page (save) so only WP auth works.
- Token Scope: By default the token scope is "worker" which only permits calling `/workers/trigger`. Setting scope to "full" (in Settings) allows all endpoints documented here. Developers can filter `redis_queue_demo_token_allowed_routes` or `redis_queue_demo_token_scope_allow` to fine-tune access.
- Token Scope: By default the token scope is "worker" which only permits calling `/workers/trigger`. Setting scope to "full" (in Settings) allows all endpoints documented here. Developers can filter `redis_queue_token_allowed_routes` or `redis_queue_token_scope_allow` to fine-tune access.
- Rate Limiting: Token calls are limited per token per minute (default 60). Exceeding returns HTTP 429 `rate_limited` error.
- Request Logging: If enabled in settings, each call in this namespace is logged (JSON lines) containing timestamp, route, status, auth method, scope result, rate-limit flag, WP user ID (if any), and IP.

Expand Down Expand Up @@ -356,15 +356,15 @@ Fields:

---
## Filters for Developers
- `redis_queue_demo_token_allowed_routes( array $routes, string $scope )` to override which routes a non-full scope token may call.
- `redis_queue_demo_token_scope_allow( bool $allowed, string $scope, WP_REST_Request $request )` for per-request dynamic decisions.
- `redis_queue_token_allowed_routes( array $routes, string $scope )` to override which routes a non-full scope token may call.
- `redis_queue_token_scope_allow( bool $allowed, string $scope, WP_REST_Request $request )` for per-request dynamic decisions.

### Filter Examples

Allow a worker-scope token to call the stats & health endpoints in addition to the default trigger route:

```php
add_filter( 'redis_queue_demo_token_allowed_routes', function( $routes, $scope ) {
add_filter( 'redis_queue_token_allowed_routes', function( $routes, $scope ) {
if ( 'worker' === $scope ) {
$routes[] = '/redis-queue/v1/stats';
$routes[] = '/redis-queue/v1/health';
Expand All @@ -376,7 +376,7 @@ add_filter( 'redis_queue_demo_token_allowed_routes', function( $routes, $scope )
Block a specific sensitive route for all tokens unless scope is full and request comes from an internal IP:

```php
add_filter( 'redis_queue_demo_token_scope_allow', function( $allowed, $scope, $request ) {
add_filter( 'redis_queue_token_scope_allow', function( $allowed, $scope, $request ) {
$internal_ip = '10.0.0.5';
$route = $request->get_route();

Expand All @@ -394,7 +394,7 @@ add_filter( 'redis_queue_demo_token_scope_allow', function( $allowed, $scope, $r
Completely disable rate-limited trigger bursts except for a whitelisted queue set (example: only allow worker token to trigger specific queues):

```php
add_filter( 'redis_queue_demo_token_scope_allow', function( $allowed, $scope, $request ) {
add_filter( 'redis_queue_token_scope_allow', function( $allowed, $scope, $request ) {
if ( ! $allowed ) { return false; }
if ( 'worker' !== $scope ) { return $allowed; }
if ( '/redis-queue/v1/workers/trigger' !== $request->get_route() ) { return $allowed; }
Expand All @@ -414,7 +414,7 @@ add_filter( 'redis_queue_demo_token_scope_allow', function( $allowed, $scope, $r
Fine-tune rate limits dynamically (example: lower limits for worker scope vs full scope). Core rate limiting currently uses a single per-minute value; this pattern shows how you might intercept before heavy routes and short-circuit access using the scope filter as a pseudo dynamic limiter:

```php
add_filter( 'redis_queue_demo_token_scope_allow', function( $allowed, $scope, $request ) {
add_filter( 'redis_queue_token_scope_allow', function( $allowed, $scope, $request ) {
if ( ! $allowed ) { return false; }

// Simple in-memory (transient) adaptive limiter per scope.
Expand Down Expand Up @@ -442,16 +442,16 @@ add_filter( 'redis_queue_demo_token_scope_allow', function( $allowed, $scope, $r
Per-token differentiated limits (example: store a map of token hashes to custom budgets). Since the raw token is available only during permission check, you could extend core to capture it; here we assume you stored custom limits in an option keyed by sha256 hash:

```php
add_filter( 'redis_queue_demo_token_scope_allow', function( $allowed, $scope, $request ) {
add_filter( 'redis_queue_token_scope_allow', function( $allowed, $scope, $request ) {
if ( ! $allowed ) { return false; }

// Suppose you saved custom limits: option name 'redis_queue_demo_custom_token_limits'
// Suppose you saved custom limits: option name 'redis_queue_custom_token_limits'
// Format: [ sha256(token) => [ 'limit' => 45 ] ]
$settings = get_option( 'redis_queue_settings', array() );
if ( empty( $settings['api_token'] ) ) { return $allowed; }
$token = $settings['api_token'];
$hash = hash('sha256', $token );
$custom_limits = get_option( 'redis_queue_demo_custom_token_limits', array() );
$custom_limits = get_option( 'redis_queue_custom_token_limits', array() );
$limit = isset( $custom_limits[ $hash ]['limit'] ) ? (int) $custom_limits[ $hash ]['limit'] : 60;

$minute = gmdate('YmdHi');
Expand Down
Loading