async

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Async-First — Quick Reference

异步优先架构——速查指南

Décharger les traitements > 200 ms vers des workers en arrière-plan, pour garder l'UI/API réactives.
将耗时超过200毫秒的任务转移至后台工作进程,以保持UI/API的响应性。

Quand activer l'async

何时启用异步

CasAsync ?
Envoi d'email transactionnel
Génération PDF / export CSV
Appel API tierce > 200 ms
Traitement batch nocturne
Lecture base de données triviale
场景是否异步?
发送事务性邮件
生成PDF / 导出CSV
调用第三方API耗时>200毫秒
夜间批量处理
简单数据库查询

Cinq invariants non-négociables

五项不可妥协的原则

  1. HTTP < 200 ms. Toute opération qui dépasse ce seuil doit être déportée.
  2. Idempotence obligatoire. Un message peut être rejoué — concevoir comme tel (idempotency keys, dedupe).
  3. Retry + Dead Letter Queue. 3 tentatives, backoff exponentiel + jitter. Au-delà → DLQ + alerte.
  4. Competing consumers. 4-8 workers en parallèle pour absorber les pics.
  5. Lifecycle tracking. Logs structurés, métriques (latence, taux erreur, DLQ depth) et alertes.
  1. HTTP响应 < 200毫秒。任何超过此阈值的操作都必须转移至后台。
  2. 必须保证幂等性。消息可能会被重发——需按此设计(幂等键、去重机制)。
  3. 重试 + 死信队列。3次重试,指数退避+抖动。超过次数→死信队列+告警。
  4. 竞争消费者模式。4-8个并行工作进程以应对峰值。
  5. 生命周期追踪。结构化日志、指标(延迟、错误率、死信队列深度)及告警。

Frameworks recommandés

推荐框架

StackFrameworkNotes
SymfonySymfony MessengerTransport AMQP, Redis, Doctrine ; supports Stamps
LaravelLaravel Queue (Horizon en prod)Backed by Redis ou SQS ; supervision native
PHP framework-agnosticEcotoneDDD, sagas, scheduler, messaging unifié
Node.jsBullMQ ou RabbitMQRedis-backed avec dashboard
技术栈框架说明
SymfonySymfony Messenger支持AMQP、Redis、Doctrine传输;支持Stamps机制
LaravelLaravel Queue(生产环境搭配Horizon)基于Redis或SQS;原生支持监控
无框架PHPEcotone支持领域驱动设计(DDD)、Sagas、调度器、统一消息传递
Node.jsBullMQ 或 RabbitMQ基于Redis,附带仪表盘

Pattern minimal (Symfony Messenger)

最简实现模式(Symfony Messenger)

php
// Message (immutable DTO)
final class SendWelcomeEmail
{
    public function __construct(public readonly string $userId) {}
}

// Handler
final class SendWelcomeEmailHandler
{
    public function __invoke(SendWelcomeEmail $message): void
    {
        // Idempotency check
        if ($this->emailLog->wasSent($message->userId, 'welcome')) {
            return;
        }
        $this->mailer->sendWelcome($message->userId);
        $this->emailLog->record($message->userId, 'welcome');
    }
}

// Dispatch (controller)
$this->bus->dispatch(new SendWelcomeEmail($user->id));
php
// Message (immutable DTO)
final class SendWelcomeEmail
{
    public function __construct(public readonly string $userId) {}
}

// Handler
final class SendWelcomeEmailHandler
{
    public function __invoke(SendWelcomeEmail $message): void
    {
        // Idempotency check
        if ($this->emailLog->wasSent($message->userId, 'welcome')) {
            return;
        }
        $this->mailer->sendWelcome($message->userId);
        $this->emailLog->record($message->userId, 'welcome');
    }
}

// Dispatch (controller)
$this->bus->dispatch(new SendWelcomeEmail($user->id));

Anti-patterns critiques

需避免的反模式

  • ❌ Mettre une opération idempotente directement dans le handler sans clé d'idempotency (replay = double effet).
  • try { ... } catch (\Throwable) { /* swallow */ }
    dans un handler → le message est marqué traité alors qu'il a échoué.
  • ❌ Stocker la payload complète d'un email/PDF dans le message → préférer un ID + lookup, sinon RabbitMQ explose.
  • ❌ Pas de circuit breaker autour des appels tiers : un provider down fait monter la DLQ en flèche.
  • ❌ 在处理器中直接处理幂等操作但未设置幂等键(重发会导致重复执行)。
  • ❌ 在处理器中使用
    try { ... } catch (\Throwable) { /* swallow */ }
    →消息被标记为已处理,但实际执行失败。
  • ❌ 将邮件/PDF的完整负载存储在消息中→优先使用ID+查询,否则RabbitMQ会过载。
  • ❌ 第三方调用未使用断路器:服务提供商宕机会导致死信队列数量激增。

Pour aller plus loin

深入学习

Détails complets, patterns Laravel/Ecotone, exemples de configuration, observabilité OpenTelemetry, lifecycle events, checklists par phase : voir
@.claude/skills/async/REFERENCE.md
.
完整细节、Laravel/Ecotone实现模式、配置示例、OpenTelemetry可观测性、生命周期事件、各阶段检查清单:详见
@.claude/skills/async/REFERENCE.md