06. tháng 1 2025
Vào buổi sáng, khi kiểm tra tình trạng hoạt động của hàng đợi (queue) trong Laravel, tôi nhận thấy còn một job chưa được xử lý xong. Điều này đã kéo dài trong một thời gian mà không có dấu hiệu kết thúc.
Khi kiểm tra log hệ thống, tôi phát hiện ra rằng lỗi liên tục xuất hiện với nội dung sau:
Giá trị số vượt quá phạm vi cho phép: 1264 Giá trị vượt giới hạn cho cột 'attempts' tại dòng 1 (Câu lệnh SQL: update
jobs
setreserved_at
= xx,attempts
= 256 whereid
= xx)
Tôi cảm thấy vấn đề nằm ở kiểu dữ liệu của trường 'attempts'. Do đó, tôi quyết định kiểm tra cấu trúc bảng jobs.
| jobs | CREATE TABLE `jobs` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`queue` varchar(255) COLLATE utf8_unicode_ci NOT NULL, [tu vi ngay](/blog/nailing-document-is-very-suitable-for-enterprise-internal-knowledge-base-precipitation/)
`payload` longtext COLLATE utf8_unicode_ci NOT NULL,
`attempts` tinyint(3) unsigned NOT NULL,
`reserved_at` int(10) unsigned DEFAULT NULL,
`available_at` int(10) unsigned NOT NULL,
`created_at` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`),
KEY `jobs_queue_reserved_at_index` (`queue`,`reserved_at`)
) ENGINE=InnoDB AUTO_INCREMENT=11542 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci [789bey](/blog/sun-heart-children-cut-a-watermelon-head/) |
Như vậy, trường 'attempts' sử dụng kiểu dữ liệu tinyint(3) unsigned, và giá trị tối đa của nó là 255. Điều này giải thích tại sao khi giá trị attempts đạt đến 256 thì xảy ra lỗi "out of range".
Để tạm thời khắc phục vấn đề, tôi đã thực hiện câu lệnh sau để đặt lại giá trị attempts về 1:
update jobs set attempts = 1;
Tuy nhiên, đây chỉ là giải pháp tức thời và chưa giải quyết triệt để gốc rễ của vấn đề.
Để giải quyết triệt để, cần phải phân tích kỹ nguyên nhân gốc rễ gây ra lỗi. Trong trường hợp cụ thể này, nguyên nhân chính là do khách hàng sử dụng nhiều hệ thống quản lý thành viên khác nhau. Khi các ID thành viên từ các hệ thống này được truyền sang dịch vụ của chúng ta, có khả năng xảy ra trùng lặp. Trong khi đó, trên bảng dữ liệu của chúng ta, trường user id đã được thiết lập là khóa duy nhất (unique index). Điều này dẫn đến việc khi hai ID thành viên từ các hệ thống khác nhau trùng nhau, hệ thống sẽ nảy sinh lỗi xung đột khóa duy nhất, khiến job bị thất bại liên tục và attempts tăng lên vượt quá giới hạn cho phép.
Giải pháp cơ bản là loại bỏ ràng buộc khóa duy nhất trên trường user id và thay vào đó thêm một trường mới để lưu trữ mã số của hệ thống thành viên (ví dụ: system_code hoặc member_system_id). Như vậy, mỗi user id sẽ được liên kết với một mã số hệ thống riêng biệt, giúp tránh được tình trạng xung đột.
Bằng cách điều chỉnh cấu trúc dữ liệu như trên, chúng ta có thể đảm bảo rằng laravel queue sẽ hoạt động ổn định hơn và không gặp phải các vấn đề tương tự trong tương lai.