Add form value persistence across cache revalidation re-renders 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
263 lines
5.8 KiB
Markdown
Executable File
263 lines
5.8 KiB
Markdown
Executable File
---
|
|
name: background-tasks
|
|
description: RSX background task system including Task and Schedule attributes, immediate CLI execution, scheduled cron jobs, and async queued tasks. Use when implementing background jobs, scheduled tasks, Task::dispatch(), or working with Rsx_Service_Abstract.
|
|
---
|
|
|
|
# RSX Task System
|
|
|
|
## Overview
|
|
|
|
RSX provides a unified task execution system with three modes:
|
|
|
|
| Mode | Use Case | Tracking |
|
|
|------|----------|----------|
|
|
| Immediate CLI | Manual/interactive runs | None |
|
|
| Scheduled | Recurring cron jobs | Database |
|
|
| Queued | Async from application | Full status |
|
|
|
|
All tasks are Service methods with `#[Task]` attribute.
|
|
|
|
---
|
|
|
|
## Service Structure
|
|
|
|
Tasks live in Service classes that extend `Rsx_Service_Abstract`:
|
|
|
|
```php
|
|
class Report_Service extends Rsx_Service_Abstract
|
|
{
|
|
#[Task('Generate monthly report')]
|
|
public static function generate_report(Task_Instance $task, array $params = [])
|
|
{
|
|
$task->log("Starting report generation...");
|
|
|
|
// ... task logic
|
|
|
|
return ['status' => 'complete', 'rows' => 1500];
|
|
}
|
|
}
|
|
```
|
|
|
|
**Location**: `/rsx/services/report_service.php`
|
|
|
|
---
|
|
|
|
## Mode 1: Immediate CLI
|
|
|
|
Run tasks directly from command line:
|
|
|
|
```bash
|
|
php artisan rsx:task:run Report_Service generate_report --month=12 --year=2025
|
|
```
|
|
|
|
Characteristics:
|
|
- Synchronous execution
|
|
- Output to STDOUT
|
|
- No timeout enforcement
|
|
- No database tracking
|
|
|
|
---
|
|
|
|
## Mode 2: Scheduled (Cron)
|
|
|
|
Add `#[Schedule]` attribute with cron syntax:
|
|
|
|
```php
|
|
#[Task('Clean thumbnails daily')]
|
|
#[Schedule('0 3 * * *')] // 3am daily
|
|
public static function clean_thumbnails(Task_Instance $task, array $params = [])
|
|
{
|
|
$task->log("Starting cleanup...");
|
|
// ... cleanup logic
|
|
}
|
|
```
|
|
|
|
### Cron Syntax Examples
|
|
|
|
| Schedule | Meaning |
|
|
|----------|---------|
|
|
| `0 3 * * *` | Daily at 3am |
|
|
| `*/15 * * * *` | Every 15 minutes |
|
|
| `0 */6 * * *` | Every 6 hours |
|
|
| `0 2 * * 1` | Mondays at 2am |
|
|
| `0 0 1 * *` | First of each month |
|
|
|
|
### Cron Setup
|
|
|
|
Add to system crontab:
|
|
|
|
```bash
|
|
* * * * * cd /var/www/html && php artisan rsx:task:process
|
|
```
|
|
|
|
Characteristics:
|
|
- Automatic execution when scheduled
|
|
- Debounced (no parallel execution of same task)
|
|
- If missed, runs as soon as possible
|
|
- Database tracking (next_run_at, started_at, completed_at)
|
|
|
|
---
|
|
|
|
## Mode 3: Queued (Async)
|
|
|
|
Dispatch tasks from application code:
|
|
|
|
```php
|
|
#[Task('Transcode video', queue: 'video', timeout: 3600)]
|
|
public static function transcode(Task_Instance $task, array $params = [])
|
|
{
|
|
$task->set_status('progress', 0);
|
|
|
|
// ... transcoding logic
|
|
|
|
$task->set_status('progress', 100);
|
|
return ['output_path' => $task->get_temp_directory() . '/output.mp4'];
|
|
}
|
|
```
|
|
|
|
### Dispatching Tasks
|
|
|
|
```php
|
|
// From controller or other code
|
|
$task_id = Task::dispatch('Video_Service', 'transcode', [
|
|
'video_id' => 123,
|
|
'format' => 'mp4'
|
|
]);
|
|
|
|
// Check status later
|
|
$status = Task::status($task_id);
|
|
// Returns: pending, running, complete, failed
|
|
```
|
|
|
|
### Task Options
|
|
|
|
```php
|
|
#[Task(
|
|
'Task description',
|
|
queue: 'default', // Queue name (for worker separation)
|
|
timeout: 120, // Max execution time in seconds
|
|
retries: 3 // Retry count on failure
|
|
)]
|
|
```
|
|
|
|
---
|
|
|
|
## Task Instance Methods
|
|
|
|
The `$task` parameter provides these methods:
|
|
|
|
```php
|
|
public static function my_task(Task_Instance $task, array $params = [])
|
|
{
|
|
// Logging
|
|
$task->log("Processing item...");
|
|
$task->info("Informational message");
|
|
$task->warning("Warning message");
|
|
$task->error("Error message");
|
|
|
|
// Progress tracking (queued tasks)
|
|
$task->set_status('progress', 50);
|
|
|
|
// Temporary directory (cleaned up after task)
|
|
$temp_dir = $task->get_temp_directory();
|
|
|
|
// Check if cancellation requested
|
|
if ($task->is_cancelled()) {
|
|
return ['status' => 'cancelled'];
|
|
}
|
|
|
|
// Return result
|
|
return ['processed' => 100];
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Listing Tasks
|
|
|
|
```bash
|
|
# List all registered tasks
|
|
php artisan rsx:task:list
|
|
|
|
# List scheduled tasks with next run times
|
|
php artisan rsx:task:list --scheduled
|
|
```
|
|
|
|
---
|
|
|
|
## Common Patterns
|
|
|
|
### Data Export Task
|
|
|
|
```php
|
|
#[Task('Export contacts to CSV')]
|
|
public static function export_contacts(Task_Instance $task, array $params = [])
|
|
{
|
|
$site_id = $params['site_id'];
|
|
$contacts = Contact_Model::where('site_id', $site_id)->get();
|
|
|
|
$csv = "Name,Email,Phone\n";
|
|
foreach ($contacts as $contact) {
|
|
$csv .= "{$contact->name},{$contact->email},{$contact->phone}\n";
|
|
}
|
|
|
|
$attachment = File_Attachment_Model::create_from_string(
|
|
$csv,
|
|
'contacts-export.csv',
|
|
['site_id' => $site_id]
|
|
);
|
|
|
|
return ['file_key' => $attachment->file_key];
|
|
}
|
|
|
|
// Dispatch from controller
|
|
$task_id = Task::dispatch('Export_Service', 'export_contacts', [
|
|
'site_id' => Session::get_site_id()
|
|
]);
|
|
```
|
|
|
|
### Cleanup Task (Scheduled)
|
|
|
|
```php
|
|
#[Task('Clean old sessions')]
|
|
#[Schedule('0 4 * * *')] // 4am daily
|
|
public static function clean_sessions(Task_Instance $task, array $params = [])
|
|
{
|
|
$deleted = Session_Model::where('expires_at', '<', now()->subDays(30))
|
|
->delete();
|
|
|
|
$task->log("Deleted {$deleted} expired sessions");
|
|
return ['deleted' => $deleted];
|
|
}
|
|
```
|
|
|
|
### Long-Running Task with Progress
|
|
|
|
```php
|
|
#[Task('Process large dataset', timeout: 3600)]
|
|
public static function process_dataset(Task_Instance $task, array $params = [])
|
|
{
|
|
$items = Item_Model::where('status', 'pending')->get();
|
|
$total = count($items);
|
|
|
|
foreach ($items as $i => $item) {
|
|
// Check for cancellation
|
|
if ($task->is_cancelled()) {
|
|
return ['status' => 'cancelled', 'processed' => $i];
|
|
}
|
|
|
|
// Process item
|
|
$item->process();
|
|
|
|
// Update progress
|
|
$task->set_status('progress', round(($i + 1) / $total * 100));
|
|
}
|
|
|
|
return ['processed' => $total];
|
|
}
|
|
```
|
|
|
|
## More Information
|
|
|
|
Details: `php artisan rsx:man tasks`
|