Files
datahub/backend/app/Platform/OrderConsumer.php
T
2025-11-27 16:25:53 +08:00

105 lines
3.4 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
declare(strict_types=1);
namespace App\Platform;
use App\Entity\Parse\EntityParseFactory;
use Hyperf\Amqp\Annotation\Consumer;
use Hyperf\Amqp\Message\ConsumerMessage;
use Hyperf\Amqp\Result;
use PhpAmqpLib\Message\AMQPMessage;
use Hyperf\Di\Annotation\Inject;
use Hyperf\DbConnection\Db;
use Throwable;
#[Consumer(exchange: "main.exchange", routingKey: "order.#", queue: "orders.queue", pool: "default_consumer", nums: 1, enable: true)]
class OrderConsumer extends ConsumerMessage
{
/**
* 队列参数配置
* 必须与 RabbitMQ 中现有队列的参数完全一致,否则会报 PRECONDITION_FAILED 错误
*
* 参数说明:
* - x-message-ttl: 消息存活时间(毫秒),24小时 = 86400000ms
* - x-dead-letter-exchange: 死信交换机,用于重试机制
* - x-dead-letter-routing-key: 死信路由键
*/
protected array $queueOptions = [
'x-message-ttl' => ['I', 86400000], // 24小时 TTL
'x-dead-letter-exchange' => ['S', 'dlx.orders'], // 死信交换机
'x-dead-letter-routing-key' => ['S', 'retry'], // 死信路由键
];
protected ?array $qos = [
// AMQP 默认并没有实现此配置。
'prefetch_size' => 0,
// 同一个消费者,最高同时可以处理的消息数。
'prefetch_count' => 100,
// 因为 Hyperf 默认一个 Channel 只消费一个 队列,所以 global 设置为 true/false 效果是一样的。
'global' => false,
];
protected $entityType = 'order';
#[Inject]
protected EntityParseFactory $entityParseFactory;
public function consumeMessage($data, AMQPMessage $message): Result
{
// dump('---data');
// dump($data);
// dump('---');
dump('---message');
dump( json_decode($message->getBody(), true));
dump('---');
$parse = $this->entityParseFactory->createFromMessage($message);
// 提取 metadata
$metadata = [
'company_id' => $data['company_id'] ?? null,
'platform_id' => $data['platform_id'] ?? null,
'store_id' => $data['store_id'] ?? null,
'unique_id' => $data['unique_id'] ?? null,
];
// entityMatch 则需要实现 根据 message 的 metadata 或其他字段的数据 获取 scope 如所属的 company / platform / store 的信息。
$entity = $parse->entityMatch($metadata);
// message 中包含 raw dataraw data (数组或集合 -> 优先为集合类型 ) 则需要通过 entityMap 方法转换为 ORM 对象。
$entityMapResult = $parse->entityMap($data['raw_data'] ?? []);
// $entityMapResult 应该是一个内部元素为 Model 的集合
Db::beginTransaction();
try {
// 假设 $entityMapResult 为集合 @Collection 对象
$entityMapResult->each(function($el) use ($entity) {
$clone = clone $entity;
$clone->fill($el);
$clone->save();
});
Db::commit();
// 在数据库事务中尝试对 $entityMapResult 中的元素进行持久化,如果没有问题, 则返回 ACK,否则这是 NACK 且 回滚事务。
return Result::ACK;
} catch (Throwable $error) {
dump($error->getMessage());
Db::rollBack();
return Result::NACK;
}
}
public function isEnable(): bool
{
return parent::isEnable();
}
}