ขนมปังตัวละครต้นฉบับกำลังปล่อยเมล็ดกลมจากนาฬิกาทรายลงรางเรียงตามเวลา

Bun.randomUUIDv7: สร้าง UUID ที่เรียงตามเวลาได้โดยไม่ทำเป็น timestamp

พี่โชว์Engineering

UUID v4 กระจายตำแหน่ง insert ใน index ขณะที่เลขรันกลางต้องพึ่ง coordinator ครับ Bun.randomUUIDv7() ผสมเวลาระดับมิลลิวินาทีกับ random bits ทำให้ identifier ที่สร้างตามเวลามักเรียงทาง lexicographic ได้และยังแจกจ่ายการสร้างไปหลาย process

WHY: บัตรคิวที่มีเวลา แต่ไม่ใช่นาฬิกาทางธุรกิจ

เหมือนบัตรคิวที่พิมพ์ช่วงเวลามาด้วย จัดชั้นเอกสารง่ายกว่าเลขสุ่มล้วน แต่บัตรนั้นไม่ได้พิสูจน์ว่าเหตุการณ์ A เกิดก่อน B ทุกกรณี นาฬิกาเครื่องอาจคลาด และสองเครื่องอาจออกบัตรในมิลลิวินาทีเดียวกัน

import assert from "node:assert/strict";

const id = Bun.randomUUIDv7();
assert.match(
  id,
  /^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/,
);

const ids = Array.from({ length: 64 }, () => Bun.randomUUIDv7());
assert.deepEqual([...ids].sort(), ids);
assert.equal(new Set(ids).size, ids.length);

Identifier ไม่ใช่ authorization

UUID v7 เปิดเผยช่วงเวลาสร้างโดยประมาณ จึงไม่เหมาะเป็น secret, reset token หรือหลักฐานสิทธิ์ หาก URL ต้องเดายากก็ยังต้องมี authorization ฝั่ง server และอาจใช้ token สุ่มแยกต่างหาก อย่านำ UUID ไป log ทุกชั้นโดยไม่กำหนด retention เพราะมันเชื่อมเหตุการณ์ข้ามระบบได้

การเรียงภายใน process เป็นคุณสมบัติที่ทดสอบได้ แต่ระบบหลายเครื่องต้องรับมือ clock skew หาก business order สำคัญให้ใช้ sequence/commit position จากระบบต้นทาง ไม่ตีความ ID เป็นเวลาที่เชื่อถือได้

Recap

  • ใช้ UUID v7 เมื่อต้องการ distributed ID ที่เป็นมิตรกับ index
  • ไม่ใช้ ID แทน secret หรือ authorization
  • อย่าสรุปลำดับธุรกิจจากเวลาที่ฝังใน UUID
  • ทดสอบ behavior บน runtime/version ที่ deploy จริง