队列orm查询数据丢失
问题描述
项目正常跑了3个月. 突然在毫无征兆的情况下出现: Model在队列里面查询数据为空(实际情况是该数据一直存在), 经过大量的测试复现了下面2种情况.
第一种情况: $order = Order::query()->where(['id' => $order_id])->first();
执行之后 $order
为空, 2秒后再次执行, $order
有值
第二种情况: $order = Order::query()->where(['id' => $order_id])->first();
执行之后 $order
有值, 隔几分钟后再次执行 $order
为空
队列使用: queue
+ horizon
+ Supervisor
laravel版本: Laravel Framework 8.83.3
job文件
class JyqrJob implements ShouldQueue
{
use Batchable, Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $order_id;
/**
* 任务可尝试的次数
* @var int
*/
public $tries = 10;
/**
* 任务失败前允许的最大异常数
* @var int
*/
public $maxExceptions = 3;
/**
* Create a new job instance.
*
* @return void
*/
public function __construct(int $order_id)
{
Redis::select(0);
$this->order_id = $order_id;
}
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
try {
$order_id = $this->order_id;
Log::channel('confirm_log')->info("订单ID:[{$this->order_id}]开始分账");
$order = Order::query()->where(['id' => $order_id])->first();
//问题就在这里, 该值是有的.
if (!$order) {
//方式一 更换查询方法
Order::find($order_id);//查询无值
//方式二 指定一个数据
Order::find(1);//查询有值
//方式三 使用原生sql
$sql = 'select * from xb_order where id = '.$order_id;
$conn = new \mysqli($servername, $username, $password,$database);
$result = $conn->query($sql);
$row = mysqli_fetch_assoc($result);//查询有值
//方式四 使用artisan 命令去查询
$exitCode = Artisan::call('test:name '.$order_id);//查询无值
//方式五 使用http请求去查询
Http::get('xxx.com/api/queue/'.$order_id);//查询有值
Log::channel('confirm_log')->info("订单ID:[{$this->order_id}]未找到,结束分账");
return false;
}
//.....省略代码
} catch (\Exception $exception) {
Log::channel('confirm_log')->info("订单ID:[{$this->order_id}]分账, 队列执行异常:" . $exception->getMessage(), ['line' => $exception->getLine()]);
}
}
}
下面是日志:
第一种情况. 一开始找不到. 后面能找到
第二种情况. 一开始能找到. 后面没找到
JyqrJob
记录的日志
下面是binlog 文件:
数据是 2022-09-28 19:11:28
插入的
2022年10月12日 更新
当队列出现查询不数据时 database 的配置会出现下图的差异. 这儿只是截取 mysql
相关的差异
这是正常情况下的database 配置
- 不是
mysql
配置导致的, 但是出问题的时候mysql
标记的配置值会出现 null. - 队列查询不到值时, 在队列里面用http去请求接口进行查询是能查询到该数据的
2022年10月24日
当$order = Order::query()->where(['id' => $order_id])->first();
查询不到数据时.我尝试了以下方法
//方式一 更换查询方法
Order::find($order_id);//查询无值
//方式二 指定一个数据
Order::find(1);//查询有值
//方式三 使用原生sql
$sql = 'select * from xb_order where id = '.$order_id;
$conn = new \mysqli($servername, $username, $password,$database);
$result = $conn->query($sql);
$row = mysqli_fetch_assoc($result);//查询有值
//方式四 使用artisan 命令去查询
$exitCode = Artisan::call('test:name '.$order_id);//查询无值
//方式五 使用http请求去查询
Http::get('xxx.com/api/queue/'.$order_id);//查询有值
事务的嫌疑又增加了
问答:laravel horzion 问题 你的應該是這個問題
项目正常跑了 3 个月,那最近有什么可能的改动影响了?
感觉是mysql的问题, 但是mysql又没报错 :sweat_smile:
该不会有全局作用域吧?能记录一下sql日志吗?
!判断换成empty试试?或者用firstOr在闭包内打日志试试?
脚本跑了一晚上, 还没复现这个问题
你的事务隔离级别是哪个,这个队列是否在事务提交后才放入队列任务中的
检查一下Supervisor 消费队列是否启用了多个? 还有model的主键key配置是否正确 如果都正确 只能打印一下全链路的日志观测一下 从请求到消费的所有日志都打印一下 sql日志也加一下