Skip to main content

Getting Started

Requirements​

  • Evolution CMS 3.7+
  • PHP 8.3+
  • Composer 2.2+
  • One of: MySQL 8.0+ / MariaDB 10.5+ / PostgreSQL 10+ / SQLite 3.25+

Installation​

Step 1: Navigate to Core Directory​

cd core

Step 2: Update Composer​

composer update

Step 3: Install Package​

php artisan package:installrequire seiger/stask "*"

Step 4: Publish Assets​

php artisan vendor:publish --tag=stask

This command will publish:

  • Configuration files to core/config/app/aliases/
  • Public assets (CSS, JS, images) to public/assets/site/
  • Creates storage directory at storage/stask/

Step 5: Run Migrations​

php artisan migrate

This creates two database tables:

  • s_workers - Worker configurations
  • s_tasks - Task records and execution history

It also creates the stask permission for controlling access to the sTask interface.

Key Features​

Core Features​

  • Asynchronous Task Processing: Execute long-running tasks in the background
  • Worker System: Extensible worker architecture for different task types
  • Progress Tracking: Real-time progress monitoring via filesystem-based tracking
  • Task Management: Complete task lifecycle management (create, execute, monitor, retry)
  • Admin Interface: Built-in administrative interface for task management
  • API Integration: RESTful API for task operations
  • Automatic Discovery: Auto-discovery of worker implementations
  • File Downloads: Download task results and exported files
  • Error Handling: Comprehensive error handling and retry mechanisms

Performance Features​

  • High-Performance Caching: Multi-level worker caching (in-memory + Laravel cache)
  • Optimized Database Queries: Batch operations and query optimization
  • Memory Management: Automatic memory cleanup and resource management
  • Performance Metrics: Real-time performance monitoring and analytics
  • Cache Statistics: Detailed cache performance metrics
  • System Health Monitoring: Automated health checks and alerts

Developer Features​

  • Clean API Design: Consistent and intuitive API endpoints
  • Comprehensive Documentation: Detailed documentation with examples
  • Error Context: Detailed error information for debugging
  • Performance Analytics: Built-in performance analysis tools
  • Cache Management: API endpoints for cache control and monitoring

Step 6: Setup Cron Job​

The task worker processes pending tasks automatically. You need to configure a cron job to run it every minute:

For Linux/Unix systems:​

# Edit your crontab
crontab -e

# Add this line to run every minute
* * * * * cd /path/to/your/project && php artisan schedule:run >> /dev/null 2>&1

For shared hosting:​

You may need to use the full path to PHP:

* * * * * cd /path/to/your/project && /usr/bin/php artisan schedule:run >> /dev/null 2>&1

For cPanel:​

  1. Go to Cron Jobs in your cPanel
  2. Add a new cron job with these settings:
    • Minute: *
    • Hour: *
    • Day: *
    • Month: *
    • Weekday: *
    • Command: cd /home/username/public_html && php artisan schedule:run >> /dev/null 2>&1

Important: Replace /path/to/your/project with the actual path to your Evolution CMS installation.

Note: Workers are automatically discovered when you access the Workers tab in the admin interface. No manual discovery needed!

Where to Find the Module​

After installation, access sTask through:

Manager → Tools → Task Manager

You'll see:

  • Dashboard Tab - Task statistics and recent tasks
  • Workers Tab - Worker management and automatic discovery

Quick Start Guide​

1. Create Your First Task (Programmatically)​

use Seiger\sTask\Facades\sTask;

// Create a simple task
$task = sTask::create(
identifier: 'product_sync', // Worker identifier
action: 'import', // Action to perform
data: [ // Task data
'file' => '/path/to/products.csv',
'delimiter' => ',',
'skip_first_row' => true
],
priority: 'normal', // 'low', 'normal', 'high'
userId: evo()->getLoginUserID()
);

echo "Task #{$task->id} created successfully!\n";

2. Check Task Status​

// Get task by ID
$task = \Seiger\sTask\Models\sTaskModel::find(1);

// Check status
if ($task->isPending()) {
echo "Task is waiting to be processed\n";
}

if ($task->isRunning()) {
echo "Task is currently executing\n";
echo "Progress: {$task->progress}%\n";
}

if ($task->isFinished()) {
echo "Task is completed\n";
echo "Status: {$task->status_text}\n";
echo "Message: {$task->message}\n";
}

// Get detailed information
echo "Worker: {$task->identifier}\n";
echo "Action: {$task->action}\n";
echo "Created: {$task->created_at}\n";
echo "Started by: User #{$task->started_by}\n";

3. Process Pending Tasks​

Tasks are automatically processed by the scheduled worker command, but you can also process them programmatically:

// Process all pending tasks
$processedCount = sTask::processPendingTasks();
echo "Processed {$processedCount} tasks\n";

// Or process with custom batch size
$processedCount = sTask::processPendingTasks(batchSize: 5);

Basic Usage Examples​

Example 1: Import Products​

use Seiger\sTask\Facades\sTask;

// Create import task
$task = sTask::create(
identifier: 'product',
action: 'import',
data: [
'file' => storage_path('imports/products_2025.csv'),
'update_existing' => true,
'create_new' => true
],
priority: 'high'
);

echo "Import task created: #{$task->id}\n";

// Task will be processed automatically by worker
// You can monitor progress in admin interface

Example 2: Export Data​

// Create export task
$task = sTask::create(
identifier: 'product',
action: 'export',
data: [
'format' => 'csv',
'filters' => [
'category_id' => 5,
'active' => true
],
'fields' => ['id', 'sku', 'name', 'price', 'stock']
],
priority: 'normal'
);

// Wait for completion (in real scenario, check via admin or API)
while (!$task->fresh()->isFinished()) {
sleep(1);
}

if ($task->status === 30) { // completed
echo "Export completed!\n";
echo "Download file: {$task->result}\n";
}

Example 3: Bulk Email Campaign​

// Create email task
$task = sTask::create(
identifier: 'email_campaign',
action: 'send',
data: [
'template' => 'newsletter_2025',
'recipients' => [
['email' => 'user1@example.com', 'name' => 'John Doe'],
['email' => 'user2@example.com', 'name' => 'Jane Smith'],
// ... more recipients
],
'subject' => 'Monthly Newsletter - January 2025',
'attachments' => [
storage_path('newsletters/january_2025.pdf')
]
],
priority: 'normal'
);

Example 4: Scheduled Cleanup​

// Create cleanup task scheduled for later
$task = \Seiger\sTask\Models\sTaskModel::create([
'identifier' => 'system',
'action' => 'cleanup',
'status' => 10, // pending
'priority' => 'low',
'start_at' => now()->addHours(2), // Run in 2 hours
'meta' => [
'clean_cache' => true,
'older_than_days' => 30
]
]);

echo "Cleanup scheduled for: {$task->start_at}\n";

Worker Management​

Discover New Workers​

// Discover and register new workers
$registered = sTask::discoverWorkers();

echo "Found and registered " . count($registered) . " new workers:\n";
foreach ($registered as $worker) {
echo "- {$worker->identifier} ({$worker->scope})\n";
}

Rescan Existing Workers​

// Update metadata for existing workers
$updated = sTask::rescanWorkers();

echo "Updated " . count($updated) . " workers\n";

Clean Orphaned Workers​

// Remove workers whose classes no longer exist
$deleted = sTask::cleanOrphanedWorkers();

echo "Removed {$deleted} orphaned workers\n";

List All Workers​

// Get all workers
$allWorkers = sTask::getWorkers(activeOnly: false);

echo "Total workers: " . $allWorkers->count() . "\n\n";

foreach ($allWorkers as $worker) {
echo "Worker: {$worker->identifier}\n";
echo " Scope: {$worker->scope}\n";
echo " Title: {$worker->title}\n";
echo " Status: " . ($worker->active ? 'Active' : 'Inactive') . "\n";
echo " Class: {$worker->class}\n";
echo "\n";
}

Filter Workers by Scope​

use Seiger\sTask\Models\sWorker;

// Get only sCommerce workers
$commerceWorkers = sWorker::byScope('scommerce')
->active()
->ordered()
->get();

foreach ($commerceWorkers as $worker) {
echo "{$worker->identifier}: {$worker->title}\n";
}

Activate/Deactivate Workers​

// Activate a worker
sTask::activateWorker('product');
echo "Product worker activated\n";

// Deactivate a worker
sTask::deactivateWorker('old_import');
echo "Old import worker deactivated\n";

// Or directly via model
$worker = sWorker::where('identifier', 'product')->first();
$worker->active = true;
$worker->save();

Task Statistics​

// Get comprehensive statistics
$stats = sTask::getStats();

echo "Task Statistics:\n";
echo " Pending: {$stats['pending']}\n";
echo " Running: {$stats['running']}\n";
echo " Completed: {$stats['completed']}\n";
echo " Failed: {$stats['failed']}\n";
echo " Cancelled: {$stats['cancelled']}\n";
echo " Total: {$stats['total']}\n";

// Get pending tasks details
$pending = sTask::getPendingTasks(limit: 10);

echo "\nPending Tasks:\n";
foreach ($pending as $task) {
echo " #{$task->id}: {$task->identifier} -> {$task->action}\n";
echo " Priority: {$task->priority}\n";
echo " Created: {$task->created_at->diffForHumans()}\n";
}

Cleanup Operations​

Clean Old Tasks​

// Remove completed tasks older than 30 days
$deletedTasks = sTask::cleanOldTasks(days: 30);
echo "Deleted {$deletedTasks} old tasks\n";

// Custom cleanup
use Seiger\sTask\Models\sTaskModel;

// Remove failed tasks older than 7 days
$deleted = sTaskModel::failed()
->where('finished_at', '<', now()->subDays(7))
->delete();

echo "Deleted {$deleted} old failed tasks\n";

// Get all incomplete tasks (pending, preparing, running)
$incomplete = sTaskModel::incomplete()->get();
echo "Found " . count($incomplete) . " incomplete tasks\n";

Artisan Commands​

Task Worker​

The task worker is automatically executed by the system via cron job every minute. You don't need to run it manually.

What it does:

  • Processes all pending tasks in the queue
  • Executes tasks through their respective workers
  • Updates task progress and status
  • Cleans up old progress files when idle
  • Should be configured via cron for continuous processing (see Setup section)

Note: Workers are automatically discovered when you access the Workers tab in the admin interface. No manual discovery needed!

API Endpoints​

sTask provides a comprehensive RESTful API for task management and monitoring.

Task Management​

Start Task​

POST /stask/workers/{identifier}/tasks/{action}
Content-Type: application/json
X-CSRF-TOKEN: {csrf_token}

{
"force": true,
"batch_size": 100
}

Response:

{
"success": true,
"id": 123,
"message": "Task created successfully"
}

Get Task Progress​

GET /stask/tasks/{id}/progress

Response:

{
"success": true,
"code": 200,
"id": 123,
"status": "running",
"progress": 45,
"message": "Processing items...",
"eta": "2m 30s"
}

Download Task Result​

GET /stask/tasks/{id}/download

Returns the result file for completed tasks.

Performance Monitoring​

Get System Performance​

GET /stask/performance/summary?hours=24

Response:

{
"success": true,
"period": {
"hours": 24,
"from": "2025-01-15T00:00:00Z",
"to": "2025-01-16T00:00:00Z"
},
"tasks": {
"total": 150,
"completed": 142,
"failed": 5,
"running": 2,
"queued": 1
},
"performance": {
"success_rate": 94.67,
"average_duration": 45.2,
"average_memory": 15728640
}
}

Get Worker Statistics​

GET /stask/performance/workers?hours=24

Response:

{
"success": true,
"workers": {
"product_sync": {
"identifier": "product_sync",
"total_tasks": 50,
"success_rate": 96.0,
"average_duration": 30.5,
"last_execution": "2025-01-16T10:30:00Z"
}
}
}

Get Performance Alerts​

GET /stask/performance/alerts

Response:

{
"success": true,
"alerts": [
{
"type": "low_success_rate",
"severity": "warning",
"message": "Task success rate is below threshold: 92%",
"value": 92,
"threshold": 95
}
]
}

Cache Management​

Get Cache Statistics​

GET /stask/cache/stats

Response:

{
"success": true,
"cache_stats": {
"hits": 1250,
"misses": 150,
"evictions": 25,
"hit_rate": 89.29,
"cache_size": 75,
"memory_usage": 52428800
}
}

Clear Cache​

POST /stask/cache/clear
Content-Type: application/json
X-CSRF-TOKEN: {csrf_token}

{
"identifier": "product_sync" // Optional: clear specific worker cache
}

Response:

{
"success": true,
"message": "Cache cleared successfully"
}

Configuration Check​

If you're developing your own package that integrates with sTask, check if sTask is installed:

// Check if sTask is installed
if (evo()->getConfig('check_sTask', false)) {
// sTask is available
$task = \Seiger\sTask\Facades\sTask::create(
identifier: 'my_worker',
action: 'process',
data: []
);
} else {
// sTask not installed, use fallback
$this->processDirectly();
}

You can also check the version:

$version = evo()->getConfig('sTaskVer', 'unknown');
echo "sTask version: {$version}\n";

Storage Structure​

sTask creates the following storage structure:

storage/
└── stask/
├── 1.json # Task #1 progress snapshot
├── 2.json # Task #2 progress snapshot
└── ...

Progress Files (*.json):

  • Store task progress snapshots
  • Updated during task execution
  • Used for real-time progress tracking
  • Cleaned up automatically by TaskWorker when idle

Database Tables​

s_workers Table​

Stores worker configurations:

ColumnTypeDescription
idBIGINTPrimary key
uuidUUIDExternal system integration ID
identifierVARCHARUnique worker identifier
scopeVARCHARModule/package scope
classVARCHARWorker class name
activeBOOLEANActive status
positionINTDisplay order
settingsJSONWorker settings
hiddenINTVisibility flag
// Query examples
use Seiger\sTask\Models\sWorker;

// Get active workers
$active = sWorker::active()->get();

// Get workers by scope
$commerce = sWorker::byScope('scommerce')->get();

// Get ordered workers
$ordered = sWorker::ordered()->get();

s_tasks Table​

Stores task records:

ColumnTypeDescription
idBIGINTPrimary key
identifierVARCHARWorker identifier
actionVARCHARAction name
statusINTExecution status (10-50)
messageVARCHARStatus message
started_byINTUser ID
metaJSONTask data
resultTEXTResult data/file path
start_atTIMESTAMPScheduled start
finished_atTIMESTAMPCompletion time
attemptsINTExecution attempts
max_attemptsINTMaximum attempts
priorityVARCHARTask priority
progressINTProgress percentage
// Query examples
use Seiger\sTask\Models\sTaskModel;

// Get pending tasks
$pending = sTaskModel::pending()->get();

// Get running tasks
$running = sTaskModel::running()->get();

// Get completed tasks
$completed = sTaskModel::completed()->get();

// Get failed tasks
$failed = sTaskModel::failed()->get();

// Get tasks by identifier
$productTasks = sTaskModel::byIdentifier('product')->get();

// Get tasks by action
$imports = sTaskModel::byAction('import')->get();

// Get high priority tasks
$urgent = sTaskModel::highPriority()->get();

Next Steps​

Troubleshooting​

Tasks Not Processing​

  1. Check if workers are active:
$worker = \Seiger\sTask\Models\sWorker::where('identifier', 'product')->first();
if (!$worker->active) {
echo "Worker is inactive!\n";
}
  1. Check task status:
$task = \Seiger\sTask\Models\sTaskModel::find(1);
echo "Status: {$task->status_text}\n";
echo "Message: {$task->message}\n";

Workers Not Discovered​

  1. Check if class implements TaskInterface:
class MyWorker implements \Seiger\sTask\Contracts\TaskInterface
{
// ...
}
  1. Verify your worker is in a valid Composer package and not in system namespaces (Illuminate, Symfony, etc.)

  2. Access the Workers tab in admin interface to trigger automatic discovery

Permission Issues​

If you get permission errors for storage:

chmod -R 755 storage/stask
chown -R www-data:www-data storage/stask

Or through PHP:

$path = storage_path('stask');
if (!is_writable($path)) {
chmod($path, 0755);
}