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 externally executed long-running tasks in Laravel (e.g., AWS Rekognition) by polling for status. Define tasks with a check() method returning ContinueChecking or StopChecking, store metadata, and run checks on a configurable interval until completion.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require spatie/laravel-long-running-tasks
    

    Publish the config (optional):

    php artisan vendor:publish --provider="Spatie\LongRunningTasks\LongRunningTasksServiceProvider"
    
  2. Define a Task Model: Extend Spatie\LongRunningTasks\LongRunningTask and implement getTaskId() and getStatus():

    use Spatie\LongRunningTasks\LongRunningTask;
    
    class MyExternalTask extends LongRunningTask
    {
        public function getTaskId(): string
        {
            return 'external-task-id-123';
        }
    
        public function getStatus(): string
        {
            return $this->externalService->getStatus();
        }
    }
    
  3. Run the Poller: Add a cron job to poll task statuses (e.g., every minute):

    * * * * * php artisan long-running:tasks:check
    
  4. Trigger a Task: Start a task and return immediately:

    $task = MyExternalTask::create([
        'data' => ['key' => 'value'],
    ]);
    $task->start();
    

First Use Case: AWS Rekognition

// Start a Rekognition job
$task = new RekognitionTask($imageId);
$task->start();

// Return immediately; the task will poll for completion
return response()->json(['task_id' => $task->id]);

Implementation Patterns

Workflow: Polling & Status Updates

  1. Task Creation:

    $task = MyTask::create(['input' => $data]);
    $task->start(); // Triggers initial poll
    
  2. Polling Logic: Override getStatus() to query the external service:

    public function getStatus(): string
    {
        $response = Http::get("https://api.example.com/status/{$this->getTaskId()}");
        return $response->json()['status'];
    }
    
  3. Result Handling: Implement handleResult() for post-completion actions:

    public function handleResult(TaskResult $result)
    {
        if ($result === TaskResult::SUCCESS) {
            $this->processSuccess();
        }
    }
    

Integration Tips

  • Queue Integration: Use Laravel queues to defer polling (e.g., dispatch(new CheckTaskJob($task))).

    class CheckTaskJob implements ShouldQueue
    {
        use Dispatchable, InteractsWithQueue;
    
        public function handle()
        {
            $task = MyTask::find($this->taskId);
            $task->checkStatus();
        }
    }
    
  • Webhooks + Polling: Combine with webhooks for efficiency:

    public function getStatus(): string
    {
        if ($this->isWebhookReceived()) {
            return TaskResult::SUCCESS;
        }
        return $this->pollExternalService();
    }
    
  • Retry Logic: Use shouldRetry() to control retries:

    public function shouldRetry(): bool
    {
        return $this->attempts < 5 && $this->getStatus() === 'PENDING';
    }
    

Gotchas and Tips

Pitfalls

  1. Infinite Polling:

    • Without shouldRetry(), tasks may poll indefinitely.
    • Fix: Always implement shouldRetry() to limit attempts.
  2. Race Conditions:

    • Concurrent polls can overwrite statuses.
    • Fix: Use database transactions or optimistic locking:
      public function checkStatus()
      {
          DB::transaction(function () {
              $this->updateStatus();
          });
      }
      
  3. Stale Data:

    • External services may return cached/stale statuses.
    • Fix: Add a lastCheckedAt field and validate freshness:
      public function getStatus(): string
      {
          if ($this->lastCheckedAt->diffInMinutes() > 5) {
              throw new \RuntimeException('Stale data');
          }
          return $this->externalService->getStatus();
      }
      

Debugging

  • Log Polling: Enable debug mode in config:

    'debug' => env('LONG_RUNNING_TASKS_DEBUG', false),
    

    Logs will show polling attempts and status changes.

  • Manual Checks: Use Artisan to force-check a task:

    php artisan long-running:tasks:check --task=1
    

Extension Points

  1. Custom Statuses: Extend TaskResult enum or add a customStatus field:

    public function getStatus(): string
    {
        return match ($this->externalStatus) {
            'PROCESSING' => TaskResult::IN_PROGRESS,
            'FAILED' => TaskResult::FAILURE,
            default => TaskResult::SUCCESS,
        };
    }
    
  2. Task Timeouts: Add a timeoutAt field and cancel tasks automatically:

    public function checkStatus()
    {
        if (now()->gt($this->timeoutAt)) {
            $this->markAsFailed('Timeout');
        }
    }
    
  3. Event Listeners: Listen for task events (e.g., TaskStarted, TaskCompleted):

    public function boot()
    {
        LongRunningTask::started(fn ($task) => Log::info("Task started: {$task->id}"));
    }
    

Config Quirks

  • Polling Interval: Adjust polling_interval in config (default: 60 seconds).

    'polling_interval' => env('LONG_RUNNING_TASKS_POLLING_INTERVAL', 60),
    
  • Queue Connection: Specify a queue for polling jobs:

    'queue_connection' => env('LONG_RUNNING_TASKS_QUEUE', 'default'),
    
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.
davejamesmiller/laravel-breadcrumbs
artisanry/parsedown
christhompsontldr/phpsdk
enqueue/dsn
bunny/bunny
enqueue/test
enqueue/null
enqueue/amqp-tools
milesj/emojibase
bower-asset/punycode
bower-asset/inputmask
bower-asset/jquery
bower-asset/yii2-pjax
laravel/nova
spatie/laravel-mailcoach
spatie/laravel-superseeder
laravel/liferaft
nst/json-test-suite
danielmiessler/sec-lists
jackalope/jackalope-transport