队列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()]);
        }
    }
}

下面是日志:
第一种情况. 一开始找不到. 后面能找到
Laravel
第二种情况. 一开始能找到. 后面没找到

JyqrJob记录的日志
Model在队列查询数据为空

下面是binlog 文件:
数据是 2022-09-28 19:11:28插入的
Laravel

2022年10月12日 更新

当队列出现查询不数据时 database 的配置会出现下图的差异. 这儿只是截取 mysql 相关的差异

Model在队列查询数据丢失

这是正常情况下的database 配置
Model在队列查询数据丢失

  1. 不是mysql配置导致的, 但是出问题的时候 mysql 标记的配置值会出现 null.
  2. 队列查询不到值时, 在队列里面用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);//查询有值
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 15
陈先生

事务的嫌疑又增加了

1年前 评论
v1i555 (楼主) 1年前

问答:laravel horzion 问题 你的應該是這個問題

1年前 评论
v1i555 (楼主) 1年前

项目正常跑了 3 个月,那最近有什么可能的改动影响了?

1年前 评论
v1i555 (楼主) 1年前
php_yt (作者) 1年前
v1i555 (楼主) 1年前

感觉是mysql的问题, 但是mysql又没报错 :sweat_smile:

1年前 评论

该不会有全局作用域吧?能记录一下sql日志吗?

1年前 评论
v1i555 (楼主) 1年前

!判断换成empty试试?或者用firstOr在闭包内打日志试试?

1年前 评论

脚本跑了一晚上, 还没复现这个问题

1年前 评论

你的事务隔离级别是哪个,这个队列是否在事务提交后才放入队列任务中的

11个月前 评论

检查一下Supervisor 消费队列是否启用了多个? 还有model的主键key配置是否正确 如果都正确 只能打印一下全链路的日志观测一下 从请求到消费的所有日志都打印一下 sql日志也加一下

11个月前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!