skills/dykyi-roman/awesome-claude-code/acc-check-async-patterns

acc-check-async-patterns

SKILL.md

Async Patterns Audit

Analyze PHP code for synchronous operations that should be handled asynchronously to improve response times and system resilience.

Detection Patterns

1. Email Sending in Request Cycle

// CRITICAL: Blocking email send in HTTP request
class RegistrationController
{
    public function register(Request $request): Response
    {
        $user = $this->userService->create($request->validated());
        $this->mailer->send(new WelcomeEmail($user));  // Blocks 2-5 seconds!
        return new Response('Registered', 201);
        // User waits for email server response
    }
}

// CORRECT: Dispatch to queue
class RegistrationController
{
    public function register(Request $request): Response
    {
        $user = $this->userService->create($request->validated());
        $this->messageBus->dispatch(new SendWelcomeEmail($user->id()));
        return new Response('Registered', 201);
        // Response immediate, email sent by worker
    }
}

2. External API Call in Request Path

// CRITICAL: Third-party API call blocks request
class OrderController
{
    public function create(Request $request): Response
    {
        $order = $this->orderService->create($request->validated());
        $tracking = $this->shippingApi->createShipment($order);  // 1-10 seconds!
        $this->notificationApi->send($order->userId(), 'Order created');  // 1-3 seconds!
        $this->analyticsApi->track('order_created', $order->toArray());   // 0.5-2 seconds!
        return new Response($order, 201);
        // Total: 3-15 seconds blocked!
    }
}

// CORRECT: Only essential ops synchronous
class OrderController
{
    public function create(Request $request): Response
    {
        $order = $this->orderService->create($request->validated());
        // Async: shipping, notifications, analytics
        $this->eventBus->dispatch(new OrderCreated($order->id()));
        return new Response($order, 201);
    }
}

3. PDF/Report Generation in Request

// CRITICAL: Heavy processing blocks request
class ReportController
{
    public function generate(Request $request): Response
    {
        $data = $this->reportService->collectData($request->get('dateRange'));  // 5-30s
        $pdf = $this->pdfGenerator->generate($data);  // 2-10s
        return new Response($pdf, 200, ['Content-Type' => 'application/pdf']);
        // User stares at spinner for 30+ seconds
    }
}

// CORRECT: Async generation with polling/webhook
class ReportController
{
    public function request(Request $request): Response
    {
        $jobId = $this->reportService->requestGeneration($request->get('dateRange'));
        return new Response(['jobId' => $jobId, 'status' => 'processing'], 202);
    }

    public function status(string $jobId): Response
    {
        $job = $this->reportService->getStatus($jobId);
        return new Response($job); // { status: 'completed', downloadUrl: '...' }
    }
}

4. Image/File Processing in Request

// CRITICAL: Image processing in upload handler
class ImageController
{
    public function upload(Request $request): Response
    {
        $file = $request->file('image');
        $this->imageService->resize($file, [800, 600]);      // CPU intensive
        $this->imageService->generateThumbnail($file, [200, 200]); // CPU intensive
        $this->imageService->optimizePng($file);              // CPU intensive
        $this->cdn->upload($file);                            // Network I/O
        return new Response('Uploaded', 201);
    }
}

// CORRECT: Upload fast, process async
class ImageController
{
    public function upload(Request $request): Response
    {
        $file = $request->file('image');
        $path = $this->storage->putTemporary($file);
        $this->queue->dispatch(new ProcessImage($path));
        return new Response(['status' => 'processing'], 202);
    }
}

5. Bulk Operations in Single Request

// CRITICAL: Processing 1000 items synchronously
class ImportController
{
    public function import(Request $request): Response
    {
        $rows = $this->csvParser->parse($request->file('data'));
        foreach ($rows as $row) {
            $this->productService->createOrUpdate($row); // N database operations
        }
        return new Response('Imported ' . count($rows));
        // Timeout after 30s / 100 items
    }
}

// CORRECT: Chunked async processing
class ImportController
{
    public function import(Request $request): Response
    {
        $path = $this->storage->putTemporary($request->file('data'));
        $jobId = $this->importService->startImport($path);
        return new Response(['jobId' => $jobId], 202);
    }
}

6. Webhook/Notification Fan-Out

// CRITICAL: Sending to multiple endpoints sequentially
class WebhookService
{
    public function notify(Event $event): void
    {
        $subscribers = $this->subscriberRepo->findByEvent($event->name());
        foreach ($subscribers as $subscriber) {
            $this->httpClient->post($subscriber->url(), $event->payload());
            // Each call: 1-5 seconds. 10 subscribers = 10-50 seconds!
        }
    }
}

// CORRECT: Dispatch to queue
class WebhookService
{
    public function notify(Event $event): void
    {
        $subscribers = $this->subscriberRepo->findByEvent($event->name());
        foreach ($subscribers as $subscriber) {
            $this->queue->dispatch(new DeliverWebhook($subscriber->id(), $event));
        }
    }
}

Grep Patterns

# Email sending in controllers/use cases
Grep: "->send\(.*Mail|->send\(.*Email|mailer->send" --glob "**/*Controller*.php"
Grep: "->send\(.*Mail|->send\(.*Email|mailer->send" --glob "**/*UseCase*.php"

# External API calls in request path
Grep: "->post\(|->get\(|->request\(" --glob "**/*Controller*.php"
Grep: "->post\(|->get\(|->request\(" --glob "**/*Action*.php"

# PDF generation
Grep: "pdf->generate|generatePdf|Dompdf|Snappy|mpdf" --glob "**/*Controller*.php"

# Image processing
Grep: "imagecreatefrom|GdImage|Imagick|InterventionImage" --glob "**/*Controller*.php"

# Bulk operations
Grep: "foreach.*->create\(|foreach.*->save\(|foreach.*->update\(" --glob "**/*Controller*.php"

# Sequential HTTP calls in loop
Grep: "foreach.*->post\(|foreach.*->send\(" --glob "**/*.php"

Severity Classification

Pattern Severity
Email sending in request cycle πŸ”΄ Critical
Multiple external API calls in request πŸ”΄ Critical
PDF/report generation in request 🟠 Major
Image processing in request 🟠 Major
Bulk import without chunking 🟠 Major
Webhook fan-out synchronously 🟑 Minor

Output Format

### Async Pattern: [Description]

**Severity:** πŸ”΄/🟠/🟑
**Location:** `file.php:line`
**Estimated Block Time:** X-Y seconds

**Issue:**
[Synchronous operation that should be async]

**Impact:**
- Response time: +Xs per request
- Under load: thread pool exhaustion
- User experience: unacceptable wait

**Code:**
```php
// Synchronous blocking code

Fix:

// Offloaded to queue/async

Architecture: Request β†’ Queue β†’ Worker β†’ Complete

Weekly Installs
1
GitHub Stars
39
First Seen
Feb 11, 2026
Installed on
opencode1
claude-code1