sanmai/later
Later is a tiny PHP library for scheduling delayed callbacks and lightweight task execution. Queue functions to run after a given time, manage timers, and build simple background jobs without a full framework. Useful for CLI daemons and event loops.
Install the package via Composer:
composer require sanmai/later
Start by using the core Later class—no service provider or config required. The simplest use case: defer a closure to run after a delay.
use function Sanmai\Later\later;
later()->delay(fn() => file_put_contents('log.txt', time()), 5); // run in 5 seconds
For Laravel integration, inject or alias Sanmai\Later\Later via a custom service provider or facade if needed. Use it in controllers or jobs for micro-scheduling within a request lifecycle—e.g., “send a welcome email in 2 minutes only if the user completes onboarding.”
Defer non-critical work: Move logging, metrics, or notification generation outside the critical path.
later()->delay(fn() => $this->trackEvent('purchase', $data), 0); // run after response sent (in CLI)
Note: In web requests, ensure the process doesn’t exit before deferred jobs run unless using async adapters or after_response() workarounds.
Debounce rapid inputs: Suppress bursts (e.g., rapid form submissions or API calls).
$debounced = later()->debounce(fn($id) => $this->cacheUserStats($id), 3000); // 3s cooldown
$debounced($userId); // only one call will execute within 3s window
Throttle with fixed rate limits: Enforce maximum calls per window.
$throttled = later()->throttle(fn() => $this->fetchExternalData(), 5, 60); // ≤5 calls per 60 seconds
Wrap risky operations with timeouts:
$result = later()->timeout(2.5, fn() => $this->slowExternalCall());
Laravel CLI use case: Use in console commands to stagger expensive batch steps.
later()->delay(fn() => $this->processBatch($nextBatch), 5);
PHP’s single-threaded nature: Deferred callbacks don’t run asynchronously by default—they’re just scheduled to execute after the current request/script finishes (via register_shutdown_function or manual dispatch). For true async behavior in CLI, consider integrating with ReactPHP or manually forking processes (not built-in). Check the Later instance’s adapter.
Request lifecycle trap: Deferred jobs won’t run if fastcgi_finish_request() isn’t called (standard PHP-FPM) or the script exits early. To ensure execution in web requests, use later()->afterResponse(fn() => ...), or pair with Laravel’s afterResponse() method inside your controller.
State serialization: Closures passed to delay()/debounce() may fail if they capture non-serializable objects (e.g., PDO connections, file handles). Prefer stateless closures or inject only scalar/data objects.
Adapter flexibility: While no adapter is required, the package supports custom execution backends (e.g., queue workers, event loop). You can extend Sanmai\Later\Later to plug into Laravel’s Bus or Queue for complex workflows.
Debugging timeouts: Use timeout() with Psr\Log\LoggerInterface to log slow operations:
$result = later()->timeout(1.0, fn() => $this->heavyOp(),
fn() => $this->logger->warning('heavyOp timed out'));
Memory leaks in long-running scripts: In php artisan schedule:run-style jobs, avoid accumulating deferred tasks without cleanup. Reset Later state periodically or limit task counts.
How can I help you explore Laravel packages today?