shizhongqi преди 4 месеца
родител
ревизия
fa76374af9

BIN
Pasted image 20260326141152.png


+ 38 - 0
server/rabbitmq/1服务.md

@@ -0,0 +1,38 @@
+1. 配置文件:/etc/supervisord.d/rabbitmq-consumer.ini
+**这个 ini 文件什么时候需要改?**
+只在以下场景才改:
+- 你要新增独立消费者(比如单独跑 `cancelLimitBuyConsumer`)才要加新的 `[program:xxx]`
+- 想提高容错才改参数(如 `startretries`、日志路径等)
+
+2. 重启服务:
+```
+supervisorctl reread  
+supervisorctl update
+
+supervisorctl restart all
+```
+
+systemctl restart rabbitmq-server
+
+
+[http://118.178.193.23:15672](http://118.178.193.23:15672/)  
+  
+admin  
+Kn3oaz138w52kzmm9
+
+### 查询命令
+```
+rabbitmqctl list_queues name consumers messages_ready messages_unacknowledged arguments
+```
+
+在测试机先跑一条命令拿到“真因”:
+ `/usr/local/nginx/html/huahuibao/yii rabbitmq/consume stockConsumer`
+ 
+ 
+### 查看日志
+ ```
+ tail -f /var/log/rabbitmq-notify-consumer.log
+ 
+ 
+ tail -n 200 /var/log/rabbitmq-stock-consumer.log
+ ```

+ 252 - 0
server/rabbitmq/header x-delay 与 TTL+DLX 的区别.md

@@ -0,0 +1,252 @@
+你这个问题问得很关键,本质是在选 **RabbitMQ 延迟消息的两种实现模型**:
+
+* ✅ `x-delay`(插件模型)
+* ✅ `TTL + DLX`(原生模型)
+
+我直接给你讲清楚**底层机制 + 差异 + 选型建议**。
+
+---
+
+# 🧠 一、两种方案本质对比
+
+## ✅ 1. `x-delay`(基于插件:rabbitmq_delayed_message_exchange)
+
+👉 核心机制:
+
+* 消息发到 **延迟交换机(delayed exchange)**
+* 在 header 里指定:
+
+```id="ywqvyr"
+x-delay: 5000  // 毫秒
+```
+
+* RabbitMQ **内部定时器**控制投递时间
+* 时间到了才真正路由到队列
+
+👉 本质:
+
+> **消息在交换机层“延迟”**
+
+---
+
+## ✅ 2. TTL + DLX(死信队列模型)
+
+👉 核心机制:
+
+1. 消息先进入一个“延迟队列”
+2. 设置 TTL(过期时间)
+3. 过期后变成死信
+4. 被 DLX(死信交换机)转发到目标队列
+
+👉 本质:
+
+> **消息在队列里“等死(过期)”再转发**
+
+---
+
+# ⚔️ 二、核心区别(重点)
+
+## 🔥 1. 精度 & 顺序(非常关键)
+
+### x-delay
+
+* ✅ 精准延迟(毫秒级)
+* ✅ 每条消息独立计时
+* ❌ 不受队列阻塞影响
+
+---
+
+### TTL + DLX
+
+* ❌ **不精确(致命点)**
+* ❌ 队列是 FIFO
+
+👉 举个例子:
+
+```id="qswdn3"
+消息A:TTL=10秒
+消息B:TTL=1秒
+```
+
+但 A 先进队列:
+
+👉 结果:
+
+* B 必须等 A 先“死”
+* 实际延迟 > 1秒(严重不准)
+
+RabbitMQ 在这种模式下有个典型现象:队头阻塞(head-of-line blocking)。
+
+如果队头是一条更长 TTL 的消息,后面即使有短 TTL 消息,也不会提前转发死信;必须等队头先“到期并被处理”。  
+所以会出现:你新发的消息看起来该到期了,但还是一直在 `limitBuyDelayQueue`。
+
+---
+
+## 🔥 2. 实现复杂度
+
+### x-delay
+
+* ✅ 一步到位
+* ❌ 需要安装插件
+
+---
+
+### TTL + DLX
+
+* ❌ 需要:
+
+  * 延迟队列
+  * DLX
+  * 路由绑定
+* ✅ 原生支持(无需插件)
+
+---
+
+## 🔥 3. 性能 & 资源
+
+### x-delay
+
+* 内部用 **定时器 + heap(优先队列)**
+* ⚠️ 大量延迟消息 → 内存压力
+
+---
+
+### TTL + DLX
+
+* 利用队列机制
+* ✅ 更稳定(大规模场景)
+* ❌ 但不精确
+
+---
+
+## 🔥 4. 使用灵活性
+
+### x-delay
+
+* ✅ 每条消息可自定义延迟
+* ✅ 动态控制
+
+---
+
+### TTL + DLX
+
+* ❌ 如果用队列 TTL → 整个队列统一时间
+* ✔️ 可用消息 TTL(但仍有顺序问题)
+
+---
+
+## 🔥 5. 运维成本
+
+### x-delay
+
+* ❌ 需要启用插件:
+
+```bash
+rabbitmq-plugins enable rabbitmq_delayed_message_exchange
+```
+
+* ❌ 升级/集群要注意兼容性
+
+---
+
+### TTL + DLX
+
+* ✅ 官方原生支持
+* ✅ 更稳定
+
+---
+
+# 🧪 三、对比总结表
+
+| 维度     | x-delay  | TTL + DLX  |
+| ------ | -------- | ---------- |
+| 精度     | ✅ 高(毫秒级) | ❌ 低(受队列阻塞) |
+| 顺序问题   | ✅ 无      | ❌ 严重       |
+| 实现复杂度  | ✅ 简单     | ❌ 复杂       |
+| 插件依赖   | ❌ 需要     | ✅ 不需要      |
+| 大规模稳定性 | ⚠️ 一般    | ✅ 高        |
+| 灵活性    | ✅ 高      | ❌ 一般       |
+
+---
+
+# 🚀 四、怎么选(实战建议)
+
+## ✅ 推荐用 `x-delay` 的场景
+
+👉 强烈建议你用它:
+
+* 延迟时间**差异很大**
+* 对时间**精度敏感**
+* 订单系统:
+
+  * 30分钟未支付取消
+  * 自动确认收货
+* 定时任务替代
+
+👉 一句话:
+
+> **现代系统优先选 x-delay**
+
+---
+
+## ✅ 推荐用 TTL + DLX 的场景
+
+* 延迟时间**固定**
+* 不在乎精度(误差几秒~分钟)
+* 消息量极大(百万级)
+* 不想装插件
+
+---
+
+# ⚠️ 五、你必须知道的坑
+
+## 🚨 x-delay 的坑
+
+1. **不是持久调度器**
+
+   * RabbitMQ 重启 → 延迟可能丢失或偏移
+
+2. **延迟太多会吃内存**
+
+---
+
+## 🚨 TTL + DLX 的坑
+
+👉 最大坑就一个:
+
+> ❗ 延迟时间完全不准(队列阻塞)
+
+---
+
+# 🎯 六、结论(很直接)
+
+👉 如果你现在在做新系统:
+
+✅ **优先选 x-delay(主流方案)**
+
+👉 如果你是:
+
+* 金融级
+* 超大规模
+* 对稳定性 > 精度
+
+👉 再考虑 TTL + DLX
+
+---
+
+# 💡 额外建议(架构升级)
+
+如果你要做**更高级的延迟系统**:
+
+可以考虑:
+
+* Redis ZSET 延迟队列
+* 时间轮(Hashed Wheel Timer)
+* Kafka + 延迟 topic
+
+---
+
+如果你愿意,我可以帮你:
+
+👉 给你一套 **PHP / Go / Node 的 x-delay 完整生产级代码(含重试 / 幂等 / 死信)**
+👉 或帮你设计一个 **高可靠延迟任务架构(比 RabbitMQ 更稳)**

+ 37 - 0
server/rabbitmq/rabbitmq 命令集.md

@@ -0,0 +1,37 @@
+**重新声明 RabbitMQ 拓扑**
+```
+/usr/local/nginx/html/huahuibao/yii rabbitmq/declare-all
+```
+
+** **
+
+
+### 如何清空 `limitBuyDelayQueue`
+
+先停消费者(可选但建议),然后执行:
+
+```bash
+rabbitmqctl purge_queue -p / limitBuyDelayQueue
+```
+
+
+---
+
+### 生效步骤(必须做)
+
+1. 重新声明拓扑:
+```bash
+/usr/local/nginx/html/huahuibao/yii rabbitmq/declare-all
+```
+
+2. 重启消费者:
+```bash
+/usr/local/nginx/html/huahuibao/yii rabbitmq/restart-consume stockConsumer
+# 或你现有的 supervisor/systemd 重启方式
+```
+
+3. 验证:
+```bash
+rabbitmqctl list_queues name consumers messages_ready messages_unacknowledged arguments
+```
+应看到新分桶队列存在;触发后消息应进入对应分桶队列,到期后进入 `limitBuyQueue` 并被消费。

+ 61 - 0
server/rabbitmq/x-delayed-message -- 启用插件.md

@@ -0,0 +1,61 @@
+改成 `x-delayed-message`,现在延迟消息走 **header `x-delay`**,不再依赖 TTL+DLX 队列模型。
+
+---
+
+### 你需要执行的运维步骤(非常关键)
+
+1. **启用插件(RabbitMQ 服务器上执行)**
+```bash
+rabbitmq-plugins enable rabbitmq_delayed_message_exchange
+```
+下载地址:https://github.com/rabbitmq/rabbitmq-delayed-message-exchange/releases?page=2
+ 或  https://github.com/rabbitmq/rabbitmq-delayed-message-exchange/releases/download/v3.8.0/rabbitmq_delayed_message_exchange-3.8.0.ez
+
+**安装教程 -- [[安装 rabbitmq_delayed_message_exchange 插件]]**
+
+
+
+2. **重启 RabbitMQ(按你的部署方式)**
+```bash
+systemctl restart rabbitmq-server
+# 或 service rabbitmq-server restart
+```
+
+3. **停掉消费者进程**
+- 暂停 `stockConsumer`,避免拓扑变更期间消费异常。
+
+4. **清理旧拓扑(因为交换机类型从 direct 改成 x-delayed-message)**
+> 同名交换机类型不能直接覆盖,必须先删旧的再声明。
+```bash
+rabbitmqadmin delete exchange name=limitBuyDelayExchange
+rabbitmqadmin delete exchange name=limitBuyExchange
+rabbitmqadmin delete queue name=limitBuyDelayQueue
+```
+
+5. **重新声明拓扑**
+```bash
+/usr/local/nginx/html/huahuibao/yii rabbitmq/declare-all
+```
+
+6. **启动/重启消费者**
+```bash
+/usr/local/nginx/html/huahuibao/yii rabbitmq/consume stockConsumer
+
+# 或你的 supervisor/systemd 重启方式
+supervisorctl restart all
+```
+
+---
+
+### 验证命令
+
+```bash
+rabbitmqctl list_exchanges name type arguments | grep limitBuyDelayExchange
+rabbitmqctl list_bindings source_name destination_name routing_key | grep limitBuy
+rabbitmqctl list_queues name consumers messages_ready messages_unacknowledged | grep limitBuy
+```
+
+期望结果:
+- `limitBuyDelayExchange` 的类型是 `x-delayed-message`
+- `limitBuyQueue` 绑定到 `limitBuyDelayExchange / limitBuyDelayRoute`
+- 发消息后会按 `x-delay` 到时进入消费,不再卡在 `limitBuyDelayQueue`

+ 225 - 0
server/rabbitmq/安装 rabbitmq_delayed_message_exchange 插件.md

@@ -0,0 +1,225 @@
+你这里其实遇到了**两个独立问题**,我帮你逐个拆开说清楚👇
+
+---
+
+# ❌ 一、核心错误:插件不存在
+
+```bash
+rabbitmq-plugins enable rabbitmq_delayed_message_exchange
+
+Error:
+{:plugins_not_found, [:rabbitmq_delayed_message_exchange]}
+```
+
+👉 这句话的真实含义是:
+
+> **你的 RabbitMQ 根本没有这个插件文件(不是没启用,是压根没装)**
+
+---
+
+# 🧠 二、为什么会这样?
+
+rabbitmq_delayed_message_exchange 不是内置插件,它属于:
+
+👉 **第三方官方插件(需要手动安装)**
+
+RabbitMQ 默认只带基础插件,比如:
+
+* management
+* amqp_client
+
+👉 **不会自带 delayed_message_exchange**
+
+---
+
+# 🛠️ 三、正确安装步骤(必须做)
+
+## ✅ Step 1:确认 RabbitMQ 版本
+
+你刚刚这条命令失败了:
+
+```bash
+rg: command not found
+```
+
+👉 因为你没装 ripgrep(rg)
+
+换成:
+
+```bash
+rabbitmqctl status | grep "RabbitMQ version"
+```
+
+或:
+
+```bash
+rabbitmqctl status
+```
+
+找:
+
+```text
+RabbitMQ version: 3.x.x
+Erlang version: xx
+```
+
+---
+
+## ✅ Step 2:下载匹配版本插件(关键)
+
+去 GitHub 官方地址:
+
+👉 [https://github.com/rabbitmq/rabbitmq-delayed-message-exchange/releases](https://github.com/rabbitmq/rabbitmq-delayed-message-exchange/releases)
+
+⚠️ 必须选和你 RabbitMQ 版本匹配的 `.ez` 文件
+
+例如:
+
+| RabbitMQ版本 | 插件版本  |
+| ---------- | ----- |
+| 3.8.x      | 对应3.8 |
+| 3.9.x      | 对应3.9 |
+| 3.11+      | 用最新版  |
+
+---
+
+## ✅ Step 3:放到 plugins 目录
+
+先找目录:
+
+```bash
+rabbitmq-plugins directories
+```
+
+你会看到类似:
+
+```text
+Plugin directory: /usr/lib/rabbitmq/lib/rabbitmq_server-3.x.x/plugins
+```
+
+👉 把 `.ez` 文件丢进去:
+
+```bash
+cp rabbitmq_delayed_message_exchange-*.ez /usr/lib/rabbitmq/lib/.../plugins/
+```
+
+---
+
+## ✅ Step 4:启用插件
+
+```bash
+rabbitmq-plugins enable rabbitmq_delayed_message_exchange
+```
+
+如果成功会看到:
+
+```text
+The following plugins have been enabled:
+  rabbitmq_delayed_message_exchange
+```
+
+---
+
+## ✅ Step 5:重启 RabbitMQ
+
+```bash
+systemctl restart rabbitmq-server
+```
+
+---
+
+# ⚠️ 四、最容易踩的坑(你很可能中招)
+
+## 🚨 1. 版本不匹配
+
+👉 现象:
+
+```text
+Plugin is incompatible
+```
+
+---
+
+## 🚨 2. 放错目录
+
+👉 常见错误路径:
+
+```bash
+/usr/lib/rabbitmq/plugins   ❌(错)
+```
+
+👉 正确是:
+
+```bash
+/usr/lib/rabbitmq/lib/rabbitmq_server-版本号/plugins  ✅
+```
+
+---
+
+## 🚨 3. 权限问题
+
+```bash
+chown rabbitmq:rabbitmq *.ez
+```
+
+---
+
+## 🚨 4. Docker 用户(如果你是容器)
+
+👉 需要:
+
+```dockerfile
+RUN rabbitmq-plugins enable rabbitmq_delayed_message_exchange
+```
+
+或者挂载插件目录
+
+---
+
+# 🔍 五、你第二个报错(顺带解决)
+
+```bash
+rg: command not found
+```
+
+👉 rg 是:
+
+ripgrep
+
+安装:
+
+```bash
+# CentOS / RHEL
+yum install -y ripgrep
+
+# Ubuntu
+apt install ripgrep
+```
+
+👉 或直接用:
+
+```bash
+grep
+```
+
+就够了
+
+---
+
+# 🎯 六、最终结论
+
+你现在的问题一句话总结:
+
+> ❗ 不是“启用失败”,是“插件压根没安装”
+
+---
+
+# 🚀 如果你要更进一步
+
+我可以帮你:
+
+* ✅ 给你 **一套 x-delay 生产级 RabbitMQ 配置(含 exchange/queue)**
+* ✅ PHP / Go / Node 延迟消息完整代码
+* ✅ 或直接帮你设计一个 **替代 RabbitMQ 的高精度延迟队列架构(更稳)**
+
+直接说你用什么语言 👍

+ 0 - 1
server/rabbitmq/服务.md

@@ -1 +0,0 @@
-重启服务: supervisorctl restart all

+ 50 - 0
server/rabbitmq/死信.md

@@ -0,0 +1,50 @@
+### 延迟队列 -> 死信 -> 消费者
+
+
+这个结果基本可以判定:**问题不在生产端**,而在“延迟队列 -> 死信 -> 消费者”这段链路。
+
+你已经看到:
+- `限购延迟消息已发送`(生产成功)
+
+但看不到:
+- `限购延迟消息开始消费` / `ACK` / `echo limit_buy_clear---`  
+=> 说明 `stockConsumer::execute()` 根本没收到这条消息。
+
+最可能的几个点(按概率):
+
+- **`stockConsumer` 进程没跑或没重启**  
+  你改了代码后,如果消费者是老进程,可能没加载新代码。
+- **`limitBuyDelayQueue` 的死信参数未生效**  
+  队列如果早期已创建(无 `x-dead-letter-exchange`),后续改配置不会自动更新,消息会过期丢弃或卡住,不会转到 `limitBuyQueue`。
+- **`limitBuyQueue` 没有活跃 consumer**
+- **延迟队列头阻塞**(同队列里有更长 TTL 的旧消息,后面的短 TTL 消息不会按预期时间转发)
+
+---
+
+建议你现在直接做这 4 步(能最快定位):
+
+1. **重启消费者**
+   - 重启 `stockConsumer`(必须是这个名字)
+
+2. **重新声明 RabbitMQ 拓扑**
+   - 执行 `php yii rabbitmq/declare-all`
+   - 若报 `PRECONDITION_FAILED`,基本就是队列参数与现存队列不一致(尤其是 DLX 参数)
+
+3. **在 RabbitMQ 管理台检查**
+   - `limitBuyDelayQueue` 的 arguments 必须有:
+     - `x-dead-letter-exchange=limitBuyExchange`
+     - `x-dead-letter-routing-key=limitBuyRoute`
+   - `limitBuyQueue` 的 consumers 要大于 0
+
+4. **用 5 秒 TTL 做最小测试**
+   - 触发一次 `seconds=5`
+   - 观察:`limitBuyDelayQueue` 消息减少 -> `limitBuyQueue` 短暂出现 -> 被消费
+   - 同时看 `console/runtime/logs/app.log`(消费日志在这里)
+
+---
+
+如果你要,我下一步可以给你加一个**临时“链路探针”**(非常轻量):
+- 发布时把 `msgId` 写 Redis;
+- 消费到后回写 `consumed_at`;
+- 你直接查 Redis 就能知道是“没投递成功”还是“没消费到”。  
+这样不依赖日志也能断点定位。

+ 21 - 0
server/帐号数据.md

@@ -18,3 +18,24 @@ nm6tczaf
 
 云喇叭
 5022107180012
+
+
+
+redis  
+/usr/local/redis/bin/redis-cli -a byt6gc1w0aed2q7h  
+密码是:byt6gc1w0aed2q7h  
+  
+数据库:  
+mysql -uroot -pzt20152008  
+  
+  
+#启动php-fpm  
+/usr/local/php/sbin/php-fpm  
+#重启php-fpm  
+kill -USR2 `cat /usr/local/php/var/run/php-fpm.pid`  
+  
+  
+#启动nginx  
+/usr/local/nginx/sbin/nginx  
+#重启nginx  
+/usr/local/nginx/sbin/nginx -s reload

+ 25 - 4
任务小笔记/26年/3-23:定位,搜索附近批发.md

@@ -27,10 +27,31 @@
 1. 找出60公里内的(最多6家) ptStyle = 2(批发)的门店 -- 过滤条件要满足是:`actTime` int(11) NOT NULL DEFAULT '0' COMMENT '活跃时间,只记录以天为单位的时候戳,用于花店注册时推荐批发店',
 	1. actTime 由通知队列在控制,由当天的日期转成的时间戳:strttime('2026-03-21') --- 已手动加了(测试了微信、支付宝、 缺余额)
 2. 地址设置 -- admin/shop/add
-   
-3. 按省市查找 -- 给 xhShop  建立新索引
+
+
+### 非法坐标过滤与其它代码优化
+提问
 ```
-ALTER TABLE `xhShop` ADD INDEX idx_ppc (`ptStyle`, `province`, `city`)
+@common/components/mapUtil.php:77 返回是 {"status":"0","info":"INVALID_PARAMS","infocode":"20000","results":[]} url:https://restapi.amap.com/v3/distance?key=fe792548aa6e15ef4d5d501e508eaeae&origins=113.354107,22.936607|116.980498,33.636912|107.207798,34.362438|116.951246,26.265799|111.253561,23.380450|102.792351,24.889631|116.447178,33.933702|102.779806,24.913287|119.374087,25.718920|10,11|118.225497,39.614242|116.103633,38.704429&destination=118.11033013237848,24.59003445095486&type=1
 ```
 
-4. 
+commit: 
+你这个返回已经能确认根因:`INVALID_PARAMS` 是因为 `origins` 里混入了非法坐标(你给的请求里有 `10,11`),高德整批直接判失败,导致后面距离数组为空/不完整。
+
+我已直接把 `buildNearbyGhsRelations` 做了防护改造(`biz/ghs/classes/GhsClass.php`):
+
+- 增加目标门店坐标校验(为空或非法直接返回并告警)。
+- 增加起点坐标校验(非数字、超出中国范围的坐标直接过滤并告警)。
+- 去掉 `array_multisort($allDistances, ..., $validNearbyShops)` 的脆弱排序方式。
+- 改为“门店+距离”配对后 `usort`,即使某批次高德返回缺失也不会数组长度错位。
+- 高德返回空结果时记录告警并继续其它批次,避免整个流程异常中断。
+
+另外我做了校验:
+- `ReadLints`:无新 lint 错误
+- `php -l biz/ghs/classes/GhsClass.php`:语法通过
+
+你现在可以重点看两类通知日志:
+- `经纬度无效`(能定位具体哪个批发商坐标脏数据)
+- `高德批量测距返回空结果`(接口异常/限流/参数问题)
+
+如果你要,我下一步可以再补一版到 `common/components/mapUtil.php`:当高德返回 `status=0` 时,把 `info/infocode` 结构化打日志,便于线上排查。

+ 97 - 0
任务小笔记/26年/3-24:批发订单自动完成.md

@@ -0,0 +1,97 @@
+### 1.脚本一
+每天3:20,将付款超过7天到10天的之间订单,payTime,并且是待发货(status =2) 或 配送中 (status = 3),把它变成完成状态
+
+
+### 2. 脚本二
+历史订单,已经付款了的(payStatus=1),并且是待发货(status=2) 或 配送中(status=3),也要把它变成完成状态
+
+-----结合表索引查询是以 payTime 是当前时间10之前的订单且是待发货(status=2) 或 配送中(status=3)为搜索条件最佳
+
+### 表字段关键信息
+```
+`status` tinyint(4) NOT NULL DEFAULT '1' COMMENT '订单状态 1待付款 2待配送 3配送中 4已完成 5已取消 6已退款',
+
+`payStatus` tinyint(4) NOT NULL DEFAULT '0' COMMENT '0待付款 1已付款,已确认',
+`payTime` datetime NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '付款时间,确认时间',
+```
+有多个索引,其中利用索引:KEY `main_payTime` (`mainId`,`status`,`payTime`,`customId`,`clearId`,`remainDebtPrice`) USING BTREE  是最佳的。
+
+
+### AI整理后的需求
+
+我帮你把这套逻辑整理成一版**更规范、可执行、可维护**的描述,同时顺便把潜在问题也一起优化掉(你现在的描述里有一点逻辑重叠和索引利用不充分的问题)。
+
+---
+
+# ✅ 优化后的完整方案(推荐版本)
+
+## 一、业务目标(统一说明)
+
+针对**批发订单自动完结机制**:
+
+* 已付款订单(`payStatus = 1`)
+* 当前仍处于:
+
+  * 待配送(`status = 2`)
+  * 配送中(`status = 3`)
+
+在满足一定时间条件后,自动流转为:
+
+👉 已完成(`status = 4`)
+
+---
+
+## 二、脚本一(定时任务:精确窗口处理)
+
+### ⏰ 执行时间
+
+每天 **03:20** -- (我会处理好这个工作,这边只是做下说明)
+
+### 🎯 处理范围
+
+付款时间在:
+
+> **7天前 ~ 10天前之间**
+
+### 📌 条件定义(标准化)
+
+```sql
+mainId = xxx
+AND payStatus = 1
+AND status IN (2, 3)
+AND payTime BETWEEN NOW() - INTERVAL 10 DAY AND NOW() - INTERVAL 7 DAY
+```
+
+### ⚙️ 执行动作
+从上面条件定义查询出来的所有订单数据以遍历的方式一条一条的执行 
+$params = ['staffId' => 0, 'staffName' => ""];
+OrderClass::confirmReach($order, $params);
+
+---
+
+# 三、脚本二(兜底任务:历史补偿)
+
+### ⏰ 执行时间
+
+手动执行(或低频执行)
+
+### 🎯 处理范围
+
+所有历史订单中:
+
+> **付款时间超过 10 天**
+
+### 📌 条件定义
+
+```sql
+mainId = xxx
+AND payStatus = 1
+AND status IN (2, 3)
+AND payTime < NOW() - INTERVAL 10 DAY
+```
+
+### ⚙️ 执行动作
+从上面条件定义查询出来的所有订单数据以遍历的方式一条一条的执行 
+$params = ['staffId' => 0, 'staffName' => ""];
+OrderClass::confirmReach($order, $params);
+

+ 189 - 0
任务小笔记/26年/3-26:限购升级.md

@@ -0,0 +1,189 @@
+### 实现中的关键信息
+1. TODO 根据限购与特价进行价格计算的关键参数
+
+2. handleLimitBuy  -- 限购处理
+
+3. 订单取消也要处理 -- 后期处理
+
+
+
+如果填了限购数量,则显示清空时间栏
+![[Pasted image 20260326141152.png|500]]
+- 超出数量
+	-  超出后就不让买了
+	1. 如果有设置特价(则显示超出数量栏),可以让按原价继续买;也可以不让买(死卡数量)
+	2. ~~如果不卖,则可以不设置特价~~
+- 如果没库存,限购活动自动停止。库存还有,但设置了清空时间,则到了时间点自动清空
+	- 有特价的怎么处理?---- 1. 处理时,去除特价且去除限购 2. 仅去除限购
+
+**最终**
+	  
+### 要实现的地方
+- 批发花材管理
+- 零售花材管理
+### 影响处
+有二个地方:
+1. 后台开单
+2. 客户下单
+
+- 前端的:批发和零售也都加,现在是修改花材和从平台采购花材已有基础,但建新品种还没有也补。
+- 零售前端的:清已购 和 已购列表 没有也要补。
+
+### 相关接口
+- 零售端花材列表接口 -- product/ghs-item-v2?id=1571&showAll=0
+	- limitBuy 关键字
+- 零售向批发买花材 -- 
+
+- 批发更新花材接口 -- 
+
+### 缓存设置
+biz-ghs/order/classes/OrderItemClass.php -- replaceItem() 376行
+
+
+## AI 解决 -- 用 RabbitMQ 把“key 过期触发”这件事,变成延迟消息 → 到期自动投递 → 消费执行
+https://chatgpt.com/c/69c646d2-fe5c-83e8-89f4-fbd91c395997
+
+已按你的要求落地:用 RabbitMQ 在到达清空时间后,把 `OrderItemClass` 的 `limitBuy` 重置为 `0`。
+
+### 本次改动
+
+- 在 `ProductClass` 的 `createLimitBuyCache()` 中改为发布延迟消息(不再用不存在的 `sendMessage`):
+  - 文件:`biz-ghs/product/classes/ProductClass.php`
+  - 逻辑:使用 `stockProducer` 向 `limitBuyDelayExchange` 投递消息,带 `expiration`(毫秒);
+  - 消息到期后通过死信路由进入真实消费队列,触发清零。
+- 新增 RabbitMQ 延迟路由配置:
+  - 文件:`common/config/rabbitMQ.php`
+  - 新增:
+    - `limitBuyDelayExchange`、`limitBuyExchange`
+    - `limitBuyDelayQueue`(带 dead-letter 到 `limitBuyExchange`)
+    - `limitBuyQueue`
+    - 对应 bindings:`limitBuyDelayRoute`、`limitBuyRoute`
+  - 并把 `limitBuyQueue` 挂到现有 `stockConsumer`。
+- 在库存消费者中新增 `limit_buy_clear` 处理分支:
+  - 文件:`common/components/rabbitmq/stockConsumer.php`
+  - 收到到期消息后调用订单项清零方法。
+- 在订单项类新增清零方法:
+  - 文件:`biz-ghs/order/classes/OrderItemClass.php`
+  - 新方法:`clearLimitBuyByProductId($productId)`,执行 `updateByCondition(['productId' => $productId], ['limitBuy' => 0])`。
+
+### 额外修正
+
+- `createLimitBuyCache()` 参数统一为 `($productId, $seconds = 0)`,匹配当前调用方式,避免把秒数错当 `customId`。
+- 已做 `php -l` 语法检查,4 个改动文件均通过。
+
+### 你这边需要确认
+
+- 消费进程要包含 `stockConsumer`(你现在的配置已把 `limitBuyQueue` 绑定到它):
+  - `php yii rabbitmq/consume stockConsumer`
+- 首次使用新队列/交换机时,如未开启自动声明,可手动执行:
+  - `php yii rabbitmq/declare-all`
+
+如果你希望“只清空未完成订单”的 `limitBuy`,我可以再帮你把 `clearLimitBuyByProductId()` 的更新条件加上订单状态过滤。
+
+
+
+
+### 疑问
+@common/config/rabbitMQ.php:45-49 @common/config/rabbitMQ.php:122-126 这个是不是多余的?
+
+不多余,按你现在这套“延迟队列 + 死信转发”实现,这两段是**成对必需**的:
+
+- `limitBuyExchange`(`45-49`)是死信目标交换机;
+- `limitBuyQueue -> limitBuyExchange(limitBuyRoute)`(`122-126`)是把交换机路由到实际消费队列的绑定。
+
+因为 `limitBuyDelayQueue` 里配置了:
+
+- `x-dead-letter-exchange = limitBuyExchange`
+- `x-dead-letter-routing-key = limitBuyRoute`
+
+消息过期后会投到这个交换机+路由键。  
+如果删掉你标的这两段,过期消息通常会因为“找不到可路由目标”被丢弃,`limitBuy` 就不会自动清零。
+
+---
+
+如果你想精简配置,也可以改成复用现有 `stockExchange/stockQueue`,那就能去掉这两段(以及 `limitBuyQueue` 的相关配置),但要同步改 `x-dead-letter-exchange/routing-key`。我可以直接帮你改成这种精简版。
+
+链路:`cancelLimitBuyProducer -> limitBuyDelayExchange -> limitBuyDelayQueue(DLX) -> limitBuyExchange -> limitBuyQueue -> cancelLimitBuyConsumer -> OrderItemClass::clearLimitBuyByProductId()`
+
+
+
+### 风险修复
+
+有 2 个需要注意的问题(按严重度):
+
+- **高风险:重复创建限购缓存时,旧延迟消息无法失效,可能“提前清空”**
+  - 当前实现每次 `createLimitBuyCache()` 都会重新发一条延迟消息,但没有“版本号/到期时间校验”。如果同一 `productId` 在旧消息到期前又改了新的清空时间,旧消息仍会按原时间触发,导致 `OrderItemClass.limitBuy` 被提前置 0。
+  
+```2662:2672:biz-ghs/product/classes/ProductClass.php
+// 用 RabbitMQ 延迟消息在到期时清空订单项限购字段
+$message = [
+    'type' => 'limit_buy_clear',
+    'productId' => $productId,
+];
+$producer = Yii::$app->rabbitmq->getProducer('cancelLimitBuyProducer');
+$producer->publish($message, 'limitBuyDelayExchange', 'limitBuyDelayRoute', [
+    'delivery_mode' => 2,
+    'content_type' => 'application/octet-stream',
+    'expiration' => (string)($seconds * 1000),
+]);
+```
+
+- **中风险:新增了独立消费者后,需要确保进程真的在跑**
+  - 你现在把 `limitBuyQueue` 挂到了 `cancelLimitBuyConsumer`,实现上是对的;但如果线上只启动了旧的 `stockConsumer`,限购清空消息会积压不消费。
+  
+```187:193:common/config/rabbitMQ.php
+[
+    //取消限购消费者
+    'name' => 'cancelLimitBuyConsumer',
+    'callbacks' => [
+        'limitBuyQueue' => '\common\components\rabbitmq\cancelLimitBuyConsumer',
+    ]
+]
+```
+
+---
+
+其余实现链路是通的:`stockProducer -> limitBuyDelayExchange -> limitBuyDelayQueue(DLX) -> limitBuyExchange -> limitBuyQueue -> cancelLimitBuyConsumer -> OrderItemClass::clearLimitBuyByProductId()`。
+
+### 建议修复方向(优先第1条)
+
+- 在消息里增加 `expireAt`(或版本号),消费者处理前比对当前产品的“有效清空时间”,不一致就直接 `ACK` 丢弃旧消息。
+- 或者改成“只在第一次创建时发消息,后续改时间走覆盖策略+校验”。
+
+如果你要,我可以直接按“`expireAt` 防抖校验”给你补一版最小改动代码。
+
+
+### 按方案一修复
+已执行,`expireAt` 防抖校验已加上,避免旧延迟消息提前清空限购。
+
+### 我做的改动
+
+- `ProductClass::createLimitBuyCache()`  
+  - 文件:`biz-ghs/product/classes/ProductClass.php`
+  - 发送消息时新增 `clearAt`:
+    - `clearAt = time() + $seconds`
+    - 消息体新增 `clearAt`
+  - 新增 Redis 版本标记:`limit_buy_clear_at:{productId}`(`SET` 当前 `clearAt`)
+  - 当 `seconds <= 0` 时会清理该标记键。
+
+- `ProductClass` 新增两个方法  
+  - `checkLimitBuyClearMessage($productId, $clearAt)`:校验消息是否是当前有效版本  
+  - `clearLimitBuyClearMark($productId)`:清理版本标记  
+  - 并在 `cancelLimitBuy($productId)` 中也清理标记,避免遗留。
+
+- `cancelLimitBuyConsumer` 消费逻辑  
+  - 文件:`common/components/rabbitmq/cancelLimitBuyConsumer.php`
+  - 消费 `limit_buy_clear` 时新增:
+    - 校验 `clearAt` 参数
+    - 调用 `ProductClass::checkLimitBuyClearMessage(...)`
+    - 非当前版本消息直接忽略(ACK,不再重入队)
+  - 真正清空成功后,调用 `ProductClass::clearLimitBuyClearMark($productId)` 清理标记。
+
+### 校验结果
+
+- 已通过语法检查:
+  - `biz-ghs/product/classes/ProductClass.php`
+  - `common/components/rabbitmq/cancelLimitBuyConsumer.php`
+- 当前仅有一个历史 Intelephense 提示(`changePrice` 未定义),与本次改动无关。
+
+如果你愿意,我下一步可以再补一条“本地手工验证清单”(发消息 -> 等待过期 -> 验证旧消息被忽略 / 新消息生效)。