Fix code quality violations and enhance ROUTE-EXISTS-01 rule
Implement JQHTML function cache ID system and fix bundle compilation Implement underscore prefix for system tables Fix JS syntax linter to support decorators and grant exception to Task system SPA: Update planning docs and wishlists with remaining features SPA: Document Navigation API abandonment and future enhancements Implement SPA browser integration with History API (Phase 1) Convert contacts view page to SPA action Convert clients pages to SPA actions and document conversion procedure SPA: Merge GET parameters and update documentation Implement SPA route URL generation in JavaScript and PHP Implement SPA bootstrap controller architecture Add SPA routing manual page (rsx:man spa) Add SPA routing documentation to CLAUDE.md Phase 4 Complete: Client-side SPA routing implementation Update get_routes() consumers for unified route structure Complete SPA Phase 3: PHP-side route type detection and is_spa flag Restore unified routes structure and Manifest_Query class Refactor route indexing and add SPA infrastructure Phase 3 Complete: SPA route registration in manifest Implement SPA Phase 2: Extract router code and test decorators Rename Jqhtml_Component to Component and complete SPA foundation setup 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
295
app/RSpade/Core/Task/CLAUDE.md
Executable file
295
app/RSpade/Core/Task/CLAUDE.md
Executable file
@@ -0,0 +1,295 @@
|
||||
# Task System
|
||||
|
||||
RSpade provides a unified task execution system supporting immediate CLI execution, queued async tasks, and scheduled cron-based tasks.
|
||||
|
||||
## Creating Task Services
|
||||
|
||||
Task services must extend `Rsx_Service_Abstract` and use attributes to define tasks:
|
||||
|
||||
```php
|
||||
use App\RSpade\Core\Service\Rsx_Service_Abstract;
|
||||
use App\RSpade\Core\Task\Task_Instance;
|
||||
|
||||
class My_Service extends Rsx_Service_Abstract
|
||||
{
|
||||
// Simple task (can be run via CLI or dispatched to queue)
|
||||
#[Task('Description of what this task does')]
|
||||
public static function my_task(Task_Instance $task, array $params = [])
|
||||
{
|
||||
$task->info('Task is running');
|
||||
// Task logic here
|
||||
return ['result' => 'success'];
|
||||
}
|
||||
|
||||
// Scheduled task (runs automatically via cron)
|
||||
#[Task('Cleanup old records')]
|
||||
#[Schedule('0 2 * * *')] // Daily at 2 AM
|
||||
public static function cleanup(Task_Instance $task, array $params = [])
|
||||
{
|
||||
$task->info('Cleanup running');
|
||||
// Cleanup logic here
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Requirements
|
||||
|
||||
- Class MUST extend `Rsx_Service_Abstract`
|
||||
- Method MUST be `public static`
|
||||
- Method MUST have signature: `(Task_Instance $task, array $params = [])`
|
||||
- Method MUST have `#[Task('description')]` attribute
|
||||
- Scheduled tasks also need `#[Schedule('cron_expression')]` attribute
|
||||
|
||||
## Important Notes on Attributes
|
||||
|
||||
- Attributes work via reflection - NO backing PHP classes needed
|
||||
- The linter will remove `use` statements for attributes - this is INTENTIONAL and CORRECT
|
||||
- Use `#[Task]` and `#[Schedule]`, NOT `#[Task_Attribute]` or any other variation
|
||||
- Never create PHP classes for these attributes
|
||||
|
||||
## Task_Instance Methods
|
||||
|
||||
The `$task` parameter provides logging and progress tracking:
|
||||
|
||||
```php
|
||||
public static function process_items(Task_Instance $task, array $params = [])
|
||||
{
|
||||
$items = Item_Model::all();
|
||||
$total = count($items);
|
||||
|
||||
$task->info("Processing {$total} items");
|
||||
|
||||
foreach ($items as $index => $item) {
|
||||
// Update progress
|
||||
$task->progress($index + 1, $total);
|
||||
|
||||
// Log info
|
||||
$task->info("Processing item {$item->id}");
|
||||
|
||||
// Log warnings
|
||||
if ($item->status === 'pending') {
|
||||
$task->warning("Item {$item->id} is still pending");
|
||||
}
|
||||
|
||||
// Process item
|
||||
$item->process();
|
||||
}
|
||||
|
||||
$task->info("Completed processing {$total} items");
|
||||
|
||||
return ['processed' => $total];
|
||||
}
|
||||
```
|
||||
|
||||
## Running Tasks
|
||||
|
||||
### CLI Execution
|
||||
|
||||
```bash
|
||||
# List all available tasks
|
||||
php artisan rsx:task:list
|
||||
|
||||
# Run task immediately from CLI (synchronous)
|
||||
php artisan rsx:task:run Service_Class method_name
|
||||
|
||||
# Run with parameters
|
||||
php artisan rsx:task:run Service_Class method_name '{"param":"value"}'
|
||||
```
|
||||
|
||||
### Programmatic Dispatch
|
||||
|
||||
```php
|
||||
// Dispatch task to queue (async)
|
||||
use App\RSpade\Core\Task\Task;
|
||||
|
||||
Task::dispatch('Service_Class', 'method_name', ['param' => 'value']);
|
||||
|
||||
// Dispatch with delay
|
||||
Task::dispatch('Service_Class', 'method_name', ['param' => 'value'], 60); // 60 second delay
|
||||
```
|
||||
|
||||
### Scheduled Execution
|
||||
|
||||
Tasks with `#[Schedule]` attribute run automatically via cron.
|
||||
|
||||
Add to crontab:
|
||||
```cron
|
||||
* * * * * cd /var/www/html && php artisan rsx:task:process
|
||||
```
|
||||
|
||||
This runs every minute and:
|
||||
1. Processes any queued tasks
|
||||
2. Runs scheduled tasks that are due
|
||||
|
||||
## Cron Expression Syntax
|
||||
|
||||
```
|
||||
┌───────────── minute (0 - 59)
|
||||
│ ┌───────────── hour (0 - 23)
|
||||
│ │ ┌───────────── day of month (1 - 31)
|
||||
│ │ │ ┌───────────── month (1 - 12)
|
||||
│ │ │ │ ┌───────────── day of week (0 - 6) (Sunday to Saturday)
|
||||
│ │ │ │ │
|
||||
│ │ │ │ │
|
||||
* * * * *
|
||||
```
|
||||
|
||||
Common patterns:
|
||||
- `*/5 * * * *` - Every 5 minutes
|
||||
- `*/30 * * * *` - Every 30 minutes
|
||||
- `0 * * * *` - Every hour
|
||||
- `0 2 * * *` - Daily at 2 AM
|
||||
- `0 */6 * * *` - Every 6 hours
|
||||
- `0 0 * * 0` - Weekly on Sunday at midnight
|
||||
- `0 0 1 * *` - Monthly on the 1st at midnight
|
||||
- `30 2 * * 1-5` - Weekdays at 2:30 AM
|
||||
|
||||
## Task Queue
|
||||
|
||||
Tasks dispatched via `Task::dispatch()` are stored in the database queue:
|
||||
|
||||
```sql
|
||||
task_queue
|
||||
├── id (bigint)
|
||||
├── service_class (varchar)
|
||||
├── method_name (varchar)
|
||||
├── parameters (json)
|
||||
├── status (enum: pending, processing, completed, failed)
|
||||
├── attempts (int)
|
||||
├── run_at (timestamp)
|
||||
├── started_at (timestamp)
|
||||
├── completed_at (timestamp)
|
||||
├── error_message (text)
|
||||
└── timestamps
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
Tasks that throw exceptions:
|
||||
1. Are marked as `failed` in the queue
|
||||
2. Error message is logged
|
||||
3. Can be retried manually via CLI
|
||||
4. Maximum 3 automatic retry attempts
|
||||
|
||||
```php
|
||||
public static function risky_task(Task_Instance $task, array $params = [])
|
||||
{
|
||||
try {
|
||||
// Risky operation
|
||||
$result = External_API::call();
|
||||
} catch (Exception $e) {
|
||||
$task->error("API call failed: " . $e->getMessage());
|
||||
throw $e; // Re-throw to mark task as failed
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Keep tasks idempotent** - Safe to run multiple times
|
||||
2. **Log progress** for long-running tasks
|
||||
3. **Return meaningful data** for debugging
|
||||
4. **Use transactions** for database operations
|
||||
5. **Set appropriate schedules** to avoid overlap
|
||||
6. **Handle exceptions gracefully**
|
||||
7. **Keep tasks focused** - one task, one purpose
|
||||
|
||||
## Common Task Patterns
|
||||
|
||||
### Cleanup Task
|
||||
```php
|
||||
#[Task('Clean old logs')]
|
||||
#[Schedule('0 3 * * *')] // Daily at 3 AM
|
||||
public static function cleanup_logs(Task_Instance $task, array $params = [])
|
||||
{
|
||||
$cutoff = now()->subDays(30);
|
||||
$deleted = Log_Model::where('created_at', '<', $cutoff)->delete();
|
||||
|
||||
$task->info("Deleted {$deleted} old log entries");
|
||||
|
||||
return ['deleted' => $deleted];
|
||||
}
|
||||
```
|
||||
|
||||
### Import Task
|
||||
```php
|
||||
#[Task('Import data from CSV')]
|
||||
public static function import_csv(Task_Instance $task, array $params = [])
|
||||
{
|
||||
$file_path = $params['file_path'] ?? null;
|
||||
|
||||
if (!$file_path || !file_exists($file_path)) {
|
||||
throw new Exception("File not found: {$file_path}");
|
||||
}
|
||||
|
||||
$handle = fopen($file_path, 'r');
|
||||
$row_count = 0;
|
||||
|
||||
while (($data = fgetcsv($handle)) !== false) {
|
||||
$row_count++;
|
||||
$task->progress($row_count);
|
||||
|
||||
// Process row
|
||||
Model::create([
|
||||
'field1' => $data[0],
|
||||
'field2' => $data[1],
|
||||
]);
|
||||
}
|
||||
|
||||
fclose($handle);
|
||||
|
||||
$task->info("Imported {$row_count} rows");
|
||||
|
||||
return ['imported' => $row_count];
|
||||
}
|
||||
```
|
||||
|
||||
### Report Generation
|
||||
```php
|
||||
#[Task('Generate monthly report')]
|
||||
#[Schedule('0 0 1 * *')] // First day of month at midnight
|
||||
public static function monthly_report(Task_Instance $task, array $params = [])
|
||||
{
|
||||
$start = now()->subMonth()->startOfMonth();
|
||||
$end = now()->subMonth()->endOfMonth();
|
||||
|
||||
$task->info("Generating report for {$start->format('F Y')}");
|
||||
|
||||
$data = Sales_Model::whereBetween('created_at', [$start, $end])
|
||||
->get();
|
||||
|
||||
$report = Report_Generator::create($data);
|
||||
$report->save(storage_path("reports/monthly-{$start->format('Y-m')}.pdf"));
|
||||
|
||||
$task->info("Report generated successfully");
|
||||
|
||||
return [
|
||||
'period' => $start->format('F Y'),
|
||||
'records' => count($data),
|
||||
];
|
||||
}
|
||||
```
|
||||
|
||||
## Monitoring Tasks
|
||||
|
||||
View task history and status:
|
||||
|
||||
```bash
|
||||
# View pending tasks
|
||||
php artisan rsx:task:pending
|
||||
|
||||
# View failed tasks
|
||||
php artisan rsx:task:failed
|
||||
|
||||
# Retry failed task
|
||||
php artisan rsx:task:retry {task_id}
|
||||
|
||||
# Clear completed tasks older than 30 days
|
||||
php artisan rsx:task:clear --days=30
|
||||
```
|
||||
|
||||
## Service Discovery
|
||||
|
||||
The manifest system automatically discovers all services extending `Rsx_Service_Abstract` in directories configured for scanning. Ensure your service directory is included in the manifest's `scan_directories` configuration.
|
||||
Reference in New Issue
Block a user