Dữ liệu không tìm thấy khi lấy 5 phút trước thời gian hiện tại

Chào mọi người, em có trường hợp đó là khi buyer mua hàng, thì đơn hàng đó sẽ tồn tại trong 30p, nếu trong 30p merchant không phản rồi thì đơn hàng sẽ tự huỷ. Vì thế ở phút thứ 20 và phút thứ 25 sẽ cảnh báo cho merchant biết. Khi buyer mua hàng sẽ có cột là orderedAt là new Date().

Nhưng em test trường hợp là phút thứ 2 em bắn noti thì dữ liệu tìm thành công. Nhưng em để 5 phút trước thời gian hiện tại thì dữ liệu nó tìm không có. Này em sử dụng CrobTab nên 10s nó chạy lại hàm này 1 lần

    const warningExpireTime = this.timeService.get5MinutesAgo()
    console.log('warningExpireTime', warningExpireTime)

    const warningExpireOrders = await this.orderCollection.warningExpireOrders(warningExpireTime)
    console.log('------- Warning expire orders -------', warningExpireOrders)
this.orderModel.aggregate<Order>([
      {
        $match: {
          status: ORDER_STATUS.TO_PREPARE,
          orderedAt: {
            $lt: warningExpireTime
          },
          warningExpireOrder: false,
        }
      }
    ])

Nếu tớ hiểu đúng:

  • Cậu tạo 1 order, tại thời điểm T.
  • Tại thời điểm T+2, cậu tìm order đang pending tại thời điểm hiện tại để gửi notification => tìm thấy order thành công
  • Tại thời điểm T+2, cậu tìm order đang pending tại thời điểm 5 phút trước thời điểm hiện tại (tức là T-3) để gửi notification => thất bại trong việc tìm order trên

Nếu ý cậu đúng như tớ hiểu ở trên, thì order này không tồn tại ở thời điểm T-3, nên dữ liệu không có là đúng chứ? :smile:

Hm, cậu có chắc cậu dùng Crontab không?
Crontab chỉ hỗ trợ tới phút, không hỗ trợ tới giây đâu :smile:

3 Likes

dạ hong, ví dụ như này. Bây giờ em mua hàng, thì orderedAt sẽ là 16:07, rồi em sẽ lấy thời gian trước 16:07 5p sẽ là 16h02. Thì crontab 10s nó chạy 1 lần, nên cứ chạy đến khi nào nó bằng hoặc lớn hơn 16h07 thì tìm được.
Này là hình ảnh 10s nó chạy 1 lần
image

Này là hình ảnh em lấy 5p trước đó
image

Em lấy dữ liệu nó log ra và vô db truy vấn trực tiếp thì tìm được

Đây là em set run lại mỗi 10s

??
Ủa, vậy ở dòng đầu tiên trong log của cậu (dòng 2021-07-26T08:55:10.007Z), là cậu truyền orderAt tại thời điểm chính xác 2021-07-26T08:55:10.007Z phải không?
Nếu vậy thì sao tìm được nhỉ? :smile: Chí ít cậu cũng nên tìm ở khoảng từ 2021-07-26T08:55:10.007Z tới 2021-07-26T08:55:20.006Z chứ (nếu như khoảng thời gian trong mỗi lần chạy là 10s)?

2 Likes

Hm, đây là node-cron đúng không cậu? :smile:
Crontab (cái tool ở Unix system ấy) originally không support tới second đâu. Node-cron có dựa trên syntax của Crontab, nhưng hỗ trợ thêm giây (optional).

4 Likes

thì đúng là nó sẽ không tìm được, như em đã nói là orderedAt em lưu trong db là thời gian hiện tại, còn thời gian em truyền vào để tìm là 5p trước thời gian em lưu trong db. Cứ 10s nó sẽ run lại 1 lần thì nó run đến nó khi nào nó bằng hoặc lớn hơn thời gian ở orderedAt em lưu trong db thì tức là nó đã chạy trong 5p thì nó sẽ bắn noti

Cậu có thể viết chi tiết cho tớ một test của cậu được không.

Ví dụ:
Giả sử, cậu có order A với thời gian orderAt là 2021-07-26T08:55:10.018Z.
Dưới đây là lịch chạy 10s 1 lần (kỳ vọng):

  • 2021-07-26T08:50:10.007Z: Không order nào tìm thấy (5 phút trước)
  • 2021-07-26T08:50:20.007Z: Không order nào tìm thấy
  • 2021-07-26T08:50:30.007Z: Không order nào tìm thấy
  • 2021-07-26T08:55:10.007Z: Không order nào tìm thấy
  • 2021-07-26T08:55:10.018Z: OrderAt của cậu ở thời điểm này.
  • 2021-07-26T08:55:20.007Z: Tìm thấy order A, gửi noti
  • 2021-07-26T08:55:30.007Z: Tìm thấy order A, gửi noti

Dưới đây là lịch chạy thực tế:

  • 2021-07-26T08:50:10.007Z: Không order nào tìm thấy (5 phút trước)
  • 2021-07-26T08:50:20.007Z: Không order nào tìm thấy
  • 2021-07-26T08:50:30.007Z: Không order nào tìm thấy
  • 2021-07-26T08:55:10.007Z: Không order nào tìm thấy
  • 2021-07-26T08:55:10.018Z: OrderAt của cậu ở thời điểm này.
  • 2021-07-26T08:55:20.007Z: Không order nào tìm thấy
  • 2021-07-26T08:55:30.007Z: Không order nào tìm thấy

Cậu có thể đưa ví dụ như trên được không?

3 Likes

Ví dụ
Em mua hàng vào thời điểm 2021-07-26T09:39:32.803Z
Em lấy 5p trước đó là 2021-07-26T09:34:40.004Z nó không trùng khớp giây bởi vì này k chạy cùng lúc.
Sau đó cứ 10s thì sẽ là

2021-07-26T09:34:40.004Z
2021-07-26T09:34:50.006Z
2021-07-26T09:35:00.004Z
2021-07-26T09:35:10.006Z
2021-07-26T09:35:20.006Z

2021-07-26T09:39:40.803Z -> thoả điều kiện -> bắn noti -> update lại warningExpireOrder: true
2021-07-26T09:39:50.803Z -> không thoả điều kiện

Tại sao lại lấy giờ ở quá khứ nếu không set giờ trên server lùi lại. Giờ nên đẩy bài toán về tương lai để xử lý.

Mình thấy sao lại đẩy vấn đề đi xa quá về quá khứ làm gì, càng đọc càng rối rắm thế nhỉ? Để mình diễn vầy bạn xem thử có đúng không nhé.

Giả sử khách hàng (có các dòng) đặt hàng vào lúc:

7:02:14
7:03:20
7:04:01
của ngày 28/07/2021 nhé, ta sẽ đổi sang timestamp theo Unix Epoch (tính theo giây chứ không mili giây làm gì) lần lượt là:
1627430534
1627430600
1627430641

Như vậy, các đơn hàng sẽ “tự hủy” vào thời điểm:
7:32:14 => 1627430534 + 30p = 1627432334 (a)
7:33:20 => 1627430600 + 30p = 1627432400 (b)
7:34:01 => 1627430641 + 30p = 1627432441 ( c )

Vào phút thứ 25 theo block 30 phút ta chơi trò “đe dọa hủy đơn hàng”, tức là kém 5 phút so với thời điểm “xử trảm”, ta sẽ gửi notify, vậy timestamp thời điểm đó là:
1627430534 + 25p => tự tính (1)
1627430600 + 25p => tự tính (2)
1627430641 + 25p => tự tính (3)

(Không cần bàn gì về quá khứ, muốn thử nghiệm thì cho phút ngắn lại tránh ngồi đợi cả tháng :D)

Ta chạy cron trên server và đổi nó ra timestamp nó lệch giờ so với 30p, 25p cọc cạch về giây so với đơn hàng chẳng thành vấn đề vì ở đây ta không nhân chia cần bội số làm gì nên nó chệch về giây không ảnh hưởng nhiều lắm, chỉ cần đúng đến phút xem như OK.

Vậy thì khi chạy cron, ta lấy current timestamp lúc ấy rồi so sánh timestamp xem nó có lớn hơn hoặc bằng timestamp ở các ví dụ (1), (2), (3) kể trên hay chưa, nếu vừa lớn hơn 1 phát thì gửi notify ngay, và tìm ngay cái thằng timestamp nhỏ hơn có trong CSDL đánh dấu xóa (hoặc không làm gì cả, vì cron sẽ tự làm vào lần đúng thời điểm 30p)

Vào thời điểm 30p (tức cộng thêm 5 phút từ lúc gửi notify ở phút 25) thì cron chạy, nó có timestamp = N, nói cách khác, khi chạy cron mà thấy có dòng đơn hàng hàng nào nhỏ hơn timestamp ở (a), (b), © thì xóa nó đi.

Nếu hệ quản trị cơ sở dữ liệu DBMS có hỗ trợ trigger và/ hoặc stored procedure thì dùng cái đó cho nhanh thay vì phải viết shell script hoặc phải chạy phần mềm tiện ích be bé do ta viết để xóa.

Không rõ có phải chủ topic muốn giải bài toán như mình vừa diễn không?

Ý của bạn Thư viện La biblioteca @library thế nào?

3 Likes

Đây là vấn đề nè, làm sao cậu chắc chắn script được trigger ở thời gian này? :smile:
Có lẽ cậu nên chỉnh lại điều kiện tìm kiếm trong DB, tìm những order tạo trong vòng 5 phút, từ thời điểm T-5 phút (tức là từ T-5 tới T phút).
Cậu cũng nên cân nhắc đánh dấu những order nào đã được gửi notification, có lẽ cần 1 trường nho nhỏ trong DB để làm việc đó (cậu không muốn gửi notification nhiều lần đâu).

Hope it helps!

4 Likes

Oh, đó là cách hay đấy cậu @superthin :smile:

Ngoài ra, như cậu có nói, nếu cậu ấy dùng RDB, cậu ấy có thể cân nhắc dùng trigger. Tớ chỉ có 1 vấn đề với trigger, là nó sẽ add tương đối nhiều load tới database.

3 Likes
83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?