Installation:
composer require danilovl/async-bundle
Ensure Danilovl\AsyncBundle\AsyncBundle::class is registered in config/bundles.php.
First Use Case:
Inject the AsyncListener into a controller or service:
use Danilovl\AsyncBundle\AsyncListener;
public function __construct(private AsyncListener $asyncListener) {}
public function handleRequest(): Response
{
// Execute async tasks after response
$this->asyncListener->add(function () {
// Your delayed logic (e.g., logging, queue creation)
\Log::info('Async task executed');
});
return new Response('Response sent immediately!');
}
Key Files:
config/packages/async.yaml (if customization is needed).src/AsyncListener (for direct usage).Trigger Async Tasks:
Use AsyncListener::add() to queue closures or callables:
$this->asyncListener->add(function () {
// Heavy or non-critical logic
});
Dependency Injection:
Prefer constructor injection for AsyncListener in services/controllers:
public function __construct(private AsyncListener $asyncListener) {}
Integration with Symfony Events: Attach async tasks to event listeners:
$eventDispatcher->addListener(KernelEvents::RESPONSE, function (RequestEvent $event) {
$this->asyncListener->add(function () {
// Post-response logic
});
});
Batch Processing: Group related async tasks in a single closure:
$this->asyncListener->add(function () {
$this->logAnalytics();
$this->sendQueueMessage();
});
Async Services: Create dedicated services for async logic:
class AsyncAnalyticsService {
public function __construct(private AsyncListener $asyncListener) {}
public function trackEvent(string $event): void {
$this->asyncListener->add(function () use ($event) {
// Async tracking logic
});
}
}
Conditional Execution: Use closures to conditionally add tasks:
if ($shouldProcessAsync) {
$this->asyncListener->add(fn() => $this->processData());
}
Error Handling: Wrap async tasks in try-catch:
$this->asyncListener->add(function () {
try {
// Risky logic
} catch (\Throwable $e) {
\Log::error('Async task failed', ['error' => $e]);
}
});
Response Timing:
Closure Scope:
$request object) unless serialized properly.Memory Leaks:
Configuration Overrides:
async.yaml:
async:
worker_process: 'async-worker' # Custom process name
max_tasks: 10 # Limit concurrent tasks
AsyncBundle\Profiler\AsyncCollector to inspect async tasks in the Symfony Profiler.php bin/console async:restart-worker
Custom Workers:
Extend the AsyncWorker class to add pre/post-task hooks:
class CustomAsyncWorker extends AsyncWorker {
protected function beforeExecute(callable $task): void {
// Pre-task logic
}
}
Register in config/services.yaml:
services:
Danilovl\AsyncBundle\AsyncWorker:
class: App\CustomAsyncWorker
Task Prioritization:
Implement a priority queue by wrapping closures in a PriorityTask object and sorting them in the worker.
Async Middleware: Create middleware to auto-add async tasks for specific routes:
public function handle(Request $request, callable $next): Response {
$response = $next($request);
$this->asyncListener->add(function () use ($request) {
// Route-specific async logic
});
return $response;
}
How can I help you explore Laravel packages today?