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);
}