Download the PHP package dskripchenko/laravel-delayed-process without Composer

On this page you can find all versions of the php package dskripchenko/laravel-delayed-process. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package laravel-delayed-process

Laravel Delayed Process

Packagist Version

Language: 中文

Asynchronous execution of long-running operations in Laravel with UUID-based tracking, automatic retry, security allowlist, and transparent frontend interceptors for Axios, Fetch, and XHR.


Table of Contents


Features


Requirements

Dependency Version
PHP ^8.5
Laravel ^12.0
Database PostgreSQL (recommended) or MySQL/MariaDB

Installation

Publish the configuration file:

Run the migration:

Register allowed entities in config/delayed-process.php:


Quick Start

1. Create a Handler

2. Trigger a Delayed Process (Backend)

3. Status Endpoint

4. Frontend — Axios Interceptor


Architecture

Lifecycle Overview

Component Overview

Component Class Purpose
Model DelayedProcess Eloquent model — stores process state, result, logs
Builder DelayedProcessBuilder Custom Eloquent builder — whereNew(), whereStuck(), claimForExecution()
Factory DelayedProcessFactory Creates process, validates entity, dispatches job
Runner DelayedProcessRunner Executes process — claim, resolve, run, handle errors
Logger DelayedProcessLogger Buffers log entries during execution, flushes to model
Job DelayedProcessJob Laravel queue job — bridges queue to runner
Resource DelayedProcessResource JSON response format for status endpoint
Resolver CallableResolver Validates and resolves entity+method to callable
EntityConfigResolver EntityConfigResolver Resolves per-entity queue/connection/timeout config
CallbackDispatcher CallbackDispatcher Sends webhook POST on terminal status
Progress DelayedProcessProgress Updates process progress (0-100%)

Contracts

Interface Default Implementation
ProcessFactoryInterface DelayedProcessFactory
ProcessRunnerInterface DelayedProcessRunner
ProcessLoggerInterface DelayedProcessLogger
ProcessProgressInterface DelayedProcessProgress

All bindings are registered in DelayedProcessServiceProvider. Override via Laravel's service container for custom implementations.

Events

Event Fired When Properties
ProcessCreated After Factory::make() saves process process
ProcessStarted After Runner claims and starts execution process
ProcessCompleted After successful execution process
ProcessFailed After exception in execution process, exception

Process Lifecycle

Status Transitions

Status Value Description
New new Created, awaiting execution. Eligible for claiming.
Wait wait Claimed by a worker, currently executing. Blocks re-entry.
Done done Successfully completed. Result stored in data. Terminal.
Error error All retry attempts exhausted. Error details in error_message / error_trace. Terminal.
Expired expired TTL exceeded before completion. Marked by delayed:expire. Terminal.
Cancelled cancelled Manually cancelled via Builder. Terminal.

Retry Logic

  1. Worker atomically claims process: UPDATE ... SET status='wait', try=try+1 WHERE status='new'
  2. Handler executes
  3. On success: status → done, result saved to data
  4. On failure:
    • If try < attempts: status → new (eligible for retry)
    • If try >= attempts: status → error, error details saved

Project Structure


Backend API

Creating Processes

Use ProcessFactoryInterface (resolved via DI):

What happens inside make():

  1. Validates entity is in allowed_entities config
  2. Validates class and method exist
  3. Validates parameters are JSON-serializable
  4. Creates DelayedProcess model in a DB transaction (auto-generates UUIDv7, sets status=new, expires_at from TTL config)
  5. Configures job queue/connection/timeout from per-entity config
  6. Dispatches DelayedProcessJob to the queue
  7. Fires ProcessCreated event
  8. Returns the persisted model

Creating with Webhook Callback

When the process reaches a terminal status (done, error, expired, cancelled), an HTTP POST is sent to the callbackUrl with {uuid, status, data}.

Per-entity Queue Configuration

Status Endpoint Response

DelayedProcessResource returns:

Notes:

Artisan Commands

delayed:process — Synchronous Worker

Processes delayed tasks without requiring a queue worker. Useful for development or single-server deployments.

Option Default Description
--max-iterations 0 (infinite) Stop after N processes. 0 = run forever.
--sleep 5 Seconds to sleep when no processes are found.

delayed:clear — Cleanup Old Processes

Deletes terminal (done / error) processes older than a specified number of days.

Option Default Description
--days 30 Delete processes older than N days.
--chunk 500 Batch delete size for memory efficiency.

delayed:unstuck — Reset Stuck Processes

Resets processes stuck in wait status back to new so they can be retried.

Option Default Description
--timeout 60 Consider processes stuck after N minutes in wait.
--dry-run false List stuck processes without resetting them.

delayed:expire — Expire TTL Processes

Marks processes whose expires_at has passed as expired.

Option Default Description
--dry-run false Show count without modifying.

delayed:migrate-v1 — Legacy Migration

Upgrades the database schema from the legacy structure. Adds error_message / error_trace columns, converts columns to JSONB (PostgreSQL) or JSON (MySQL), creates partial/composite indexes, and adds CHECK constraint.


Frontend Interceptors

The resources/js/delayed-process/ module provides transparent interceptors that automatically detect delayed process responses and poll until completion.

How It Works

  1. Your API returns a response containing { payload: { delayed: { uuid: "..." } } }
  2. The interceptor detects the UUID
  3. It starts polling the status endpoint: GET {statusUrl}?uuid={uuid}
  4. When status becomes done, the interceptor replaces the response payload with the result data
  5. When status becomes error, expired, or cancelled, the interceptor throws a DelayedProcessError
  6. Polling requests include X-Delayed-Process-Poll: 1 header to prevent infinite loops

File Structure

File Purpose
index.ts Public exports
types.ts TypeScript types, BatchPollerConfig, DelayedProcessError
core/config.ts Default config, CSRF auto-detection, resolveConfig()
core/poller.ts pollUntilDone() — core polling loop with timeout and abort
core/batch-poller.ts BatchPoller — poll multiple UUIDs in a single request
axios/interceptor.ts applyAxiosInterceptor() — Axios response interceptor
fetch/patch.ts patchFetch() — monkey-patches window.fetch
xhr/patch.ts patchXHR() — monkey-patches XMLHttpRequest (double-patch guard)

Axios Interceptor

Fetch Patch

XHR Patch

DelayedProcessConfig

Option Type Default Description
statusUrl string '/api/common/delayed-process/status' URL for polling process status
pollingInterval number 3000 Milliseconds between poll requests
maxAttempts number 100 Maximum number of poll attempts
timeout number 300000 Total timeout in milliseconds (5 min)
headers Record<string, string> {} Extra headers for poll requests
onPoll (uuid: string, attempt: number) => void undefined Callback invoked on each poll

CSRF token from <meta name="csrf-token"> is automatically included in poll requests.

Batch Poller

For polling multiple processes at once (e.g., bulk operations):

DelayedProcessError

Thrown when a process completes with error, expired, or cancelled status, or polling times out.

Loop Prevention

All polling requests include the header X-Delayed-Process-Poll: 1. The interceptors check for this header and skip interception on poll requests, preventing infinite polling loops.


Configuration Reference

File: config/delayed-process.php

Key Type Default Description
allowed_entities array [] FQCN allowlist — string values or Entity::class => [config] keyed arrays
default_attempts int 5 Maximum retry attempts before marking as error
clear_after_days int 30 delayed:clear deletes terminal processes older than this
stuck_timeout_minutes int 60 delayed:unstuck considers wait processes stuck after this
log_sensitive_context bool false Include log context arrays in process logs
log_buffer_limit int 500 Max log entries in memory buffer per process (0 = unlimited)
callback.enabled bool false Enable webhook POST on terminal status
callback.timeout int 10 Webhook HTTP timeout in seconds
default_ttl_minutes int\|null null Default TTL for new processes (null = no expiration)
job.timeout int 300 Queue job timeout in seconds
job.tries int 1 Queue job retry attempts (separate from process attempts)
job.backoff array [30, 60, 120] Queue job backoff delays in seconds
command.sleep int 5 delayed:process sleep when idle (seconds)
command.max_iterations int 0 delayed:process iteration limit (0 = infinite)
command.throttle int 100000 delayed:process throttle between iterations (microseconds)
clear_chunk_size int 500 delayed:clear batch delete size

Database Schema

Table: delayed_processes

Column Type Default Description
id bigint PK auto-increment Primary key
uuid string(36) UNIQUE auto (UUIDv7) Unique process identifier
entity string nullable NULL FQCN of handler class
method string Handler method name
parameters jsonb / json [] Serialized invocation arguments
data jsonb / json [] Execution result payload
logs jsonb / json [] Captured log entries
status string 'new' Process status (new, wait, done, error, expired, cancelled)
attempts tinyint unsigned 5 Maximum retry attempts
try tinyint unsigned 0 Current attempt number
error_message string(1000) nullable NULL Last error message (truncated with indicator)
error_trace text nullable NULL Last error stack trace
started_at timestamptz nullable NULL Execution start time
duration_ms bigint unsigned nullable NULL Execution duration in milliseconds
callback_url string(2048) nullable NULL Webhook URL for terminal status notification
progress tinyint unsigned 0 Execution progress (0-100)
expires_at timestamptz nullable NULL Process expiration time (TTL)
created_at timestamptz NOW Creation timestamp
updated_at timestamptz NOW Last update timestamp

Indexes

PostgreSQL (partial indexes for optimal performance):

Index Condition
(status, try) WHERE status = 'new'
(created_at) WHERE status IN ('done', 'error', 'expired', 'cancelled')
(updated_at) WHERE status = 'wait'
(expires_at) WHERE status IN ('new', 'wait') AND expires_at IS NOT NULL

MySQL / MariaDB (composite indexes):

Index
(status, try)
(status, created_at)
(status, updated_at)

Constraints


Security

Entity Allowlist

Only classes listed in config('delayed-process.allowed_entities') can be executed. Attempting to create a process with an unlisted class throws EntityNotAllowedException.

Callable Validation

Before execution, CallableResolver verifies:

  1. Entity class is in the allowlist
  2. Class exists (class_exists())
  3. Method exists (method_exists())

Instantiation uses app($entity) — full Laravel DI container support.

Log Privacy

Set log_sensitive_context to false (default) to strip context arrays from captured log entries. Only log level, timestamp, and message are stored.

CSRF Protection

The frontend poller automatically reads <meta name="csrf-token"> and includes it in poll request headers. Ensure your status endpoint is behind CSRF middleware or explicitly verify the token.


Cookbook

For recipes, patterns, and troubleshooting, see the Cookbook.

Available in: 中文


Frontend Integration Guide

For a detailed step-by-step guide on integrating interceptors into Vue.js 3 and React applications, see the Frontend Interceptors Guide.

Includes: composables/hooks, progress tracking, batch polling, error handling, SSR support, and testing.


License

MIT © Denis Skripchenko


All versions of laravel-delayed-process with dependencies

PHP Build Version
Package Version
Requires php Version ^8.5
laravel/framework Version ^12.0
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package dskripchenko/laravel-delayed-process contains the following files

Loading the files please wait ...