Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Long Running Tasks Laravel Package

spatie/laravel-long-running-tasks

Monitor and poll external long-running jobs (e.g., AWS Rekognition) in Laravel. Define a task with a check() method that runs on a configurable interval, store meta/context, and automatically reschedule until it reports completion.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require spatie/laravel-long-running-tasks
    php artisan vendor:publish --tag="long-running-tasks-migrations"
    php artisan vendor:publish --tag="long-running-tasks-config"
    php artisan migrate
    

    Ensure your Laravel queues are configured (e.g., database, Redis, SQS).

  2. First Task Creation: Create a task class extending Spatie\LongRunningTask:

    namespace App\Tasks;
    
    use Spatie\LongRunningTasks\LongRunningTask;
    use Spatie\LongRunningTasks\Enums\TaskResult;
    use Spatie\LongRunningTasks\Models\LongRunningTaskLogItem;
    
    class ProcessExternalData extends LongRunningTask
    {
        public function check(LongRunningTaskLogItem $logItem): TaskResult
        {
            $data = $logItem->meta['data'];
            $isDone = $this->isProcessingComplete($data);
    
            return $isDone ? TaskResult::StopChecking : TaskResult::ContinueChecking;
        }
    
        private function isProcessingComplete(array $data): bool
        {
            // Your logic to check completion
            return false;
        }
    }
    
  3. Start the Task:

    ProcessExternalData::make()
        ->meta(['data' => $yourData])
        ->start();
    

Where to Look First

  • Config File: config/long-running-tasks.php for default settings (queue, frequency, strategies).
  • Task Logs: Database table long_running_task_log_items to inspect task statuses.
  • Job Handling: app/Jobs for custom job implementations if needed.

First Use Case

Polling an External API:

class PollExternalApi extends LongRunningTask
{
    public function check(LongRunningTaskLogItem $logItem): TaskResult
    {
        $response = Http::get($logItem->meta['api_url']);
        $status = $response->json()['status'];

        if ($status === 'completed') {
            return TaskResult::StopChecking;
        }

        return TaskResult::ContinueChecking;
    }
}

// Start with metadata
PollExternalApi::make()
    ->meta(['api_url' => 'https://api.example.com/task/123'])
    ->checkFrequencyInSeconds(15) // Custom interval
    ->start();

Implementation Patterns

Core Workflow

  1. Task Definition: Extend LongRunningTask and implement the check() method. Use TaskResult to control task lifecycle.

    class MyTask extends LongRunningTask {
        public function check(LongRunningTaskLogItem $logItem): TaskResult {
            // Business logic here
            return $this->shouldContinue ? TaskResult::ContinueChecking : TaskResult::StopChecking;
        }
    }
    
  2. Task Initialization: Use fluent methods to configure task behavior before starting:

    MyTask::make()
        ->meta(['key' => 'value']) // Pass metadata
        ->checkFrequencyInSeconds(30) // Override default frequency
        ->checkStrategy(StandardBackoffCheckStrategy::class) // Custom strategy
        ->onQueue('high-priority') // Custom queue
        ->keepCheckingForInSeconds(3600) // Timeout
        ->start();
    
  3. Error Handling: Implement onFail() to handle exceptions gracefully:

    public function onFail(LongRunningTaskLogItem $logItem, Exception $exception): ?TaskResult {
        Log::error("Task failed: " . $exception->getMessage());
        return TaskResult::ContinueChecking; // Retry or not
    }
    
  4. Monitoring: Query the LongRunningTaskLogItem model to track task statuses:

    $pendingTasks = LongRunningTaskLogItem::where('status', 'pending')->get();
    $failedTasks = LongRunningTaskLogItem::where('status', 'failed')->with('latestException')->get();
    

Integration Tips

  • Queue Workers: Ensure your queue worker (php artisan queue:work) is running to process tasks.

  • Event Listeners: Listen to task events (e.g., TaskStarted, TaskCompleted) for notifications or side effects:

    LongRunningTaskLogItem::created(function ($logItem) {
        event(new TaskStarted($logItem));
    });
    
  • Custom Models: Extend LongRunningTaskLogItem for additional fields or logic:

    class CustomTaskLog extends LongRunningTaskLogItem {
        protected $casts = [
            'custom_field' => 'string',
        ];
    }
    

    Update the config to use your custom model:

    'log_model' => App\Models\CustomTaskLog::class,
    
  • Testing: Use LongRunningTaskLogItem factories or mock the check() method in unit tests:

    $task = MyTask::make()->meta(['test' => true]);
    $this->assertEquals(TaskResult::StopChecking, $task->check($logItem));
    

Gotchas and Tips

Pitfalls

  1. Queue Stuck Jobs:

    • If tasks hang in running status, check for deadlocks or infinite loops in check().
    • Use php artisan queue:failed to inspect failed jobs and retry manually.
  2. Timeouts:

    • Tasks marked as didNotComplete may indicate:
      • External API timeouts (increase keepCheckingForInSeconds).
      • Misconfigured checkFrequencyInSeconds (e.g., too high for real-time needs).
    • Monitor stop_checking_at to debug stalled tasks.
  3. Metadata Handling:

    • Ensure meta is serializable (avoid passing objects or resources).
    • Large metadata arrays may bloat the database; consider storing IDs and fetching data separately.
  4. Strategy Misuse:

    • StandardBackoffCheckStrategy and ExponentialBackoffCheckStrategy can lead to long delays if not monitored. Use for non-critical tasks.
    • Example of exponential backoff causing delays:
      // Default: 10s, 60s, 120s, 300s, 600s
      $task->checkStrategy(ExponentialBackoffCheckStrategy::class);
      
  5. Concurrency Issues:

    • Avoid race conditions in check() by using transactions or optimistic locking if modifying shared resources.

Debugging Tips

  1. Log Task Execution: Add logging in check() to trace progress:

    Log::info("Task run #{$logItem->run_count}: Processing {$logItem->meta['item_id']}");
    
  2. Inspect Log Items: Use Tinker to debug:

    php artisan tinker
    >>> $logItem = \App\Models\LongRunningTaskLogItem::find(1);
    >>> $logItem->latest_exception; // Check last error
    >>> $logItem->meta; // Verify metadata
    
  3. Queue Monitoring:

    • Use Laravel Horizon or queue:listen to observe job processing.
    • Check failed_jobs table for exceptions.
  4. Custom Exceptions: Throw descriptive exceptions in check() to aid debugging:

    throw new \RuntimeException("Failed to fetch data for ID: {$logItem->meta['id']}");
    

Extension Points

  1. Custom Strategies: Create a new strategy by implementing Spatie\LongRunningTasks\Contracts\CheckStrategy:

    class CustomStrategy implements CheckStrategy {
        public function getCheckFrequencyInSeconds(LongRunningTaskLogItem $logItem): int {
            return $logItem->run_count > 3 ? 60 : 10;
        }
    }
    
  2. Pre/Post Hooks: Use model events to add behavior:

    LongRunningTaskLogItem::created(function ($logItem) {
        // Send notification when task starts
    });
    
    LongRunningTaskLogItem::updated(function ($logItem) {
        if ($logItem->isDirty('status') && $logItem->status === 'completed') {
            // Clean up resources
        }
    });
    
  3. Bulk Operations: Process multiple tasks in parallel by starting them with unique metadata:

    foreach ($items as $item) {
        ProcessItemTask::make()
            ->meta(['item_id' => $item->id])
            ->onQueue('bulk-processing')
            ->start();
    }
    
  4. Retry Logic: Implement custom retry logic in onFail():

    public function onFail(LongRunningTaskLogItem $logItem, Exception $exception): ?TaskResult {
        if ($logItem->attempt < 3 && $exception instanceof \HttpException) {
            return TaskResult::ContinueChecking; // Retry up to 3 times
        }
        return null; // Give up
    }
    
  5. Performance Optimization:

    • Batch database queries in check() to reduce overhead.
    • Use checkFrequencyInSeconds wisely: shorter intervals increase load but improve responsiveness.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
codraw/framework-extra-bundle
codraw/messenger
codraw/security
codraw/mailer
codraw/contracts
codraw/profiling
codraw/dependency-injection
codraw/tester
codraw/core
nexmo/api-specification
capell-app/block-library
axium/identity
cetria/laravel-dummy-models
cetria/reflection-helper
agropredict/sso-auth-bundle
evolvestudio/spam-protection
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony