1 คะแนน โดย GN⁺ 7 시간 전 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • เวิร์กโฟลว์แบบทนทาน (Durable) จะ checkpoint สถานะการทำงานลงฐานข้อมูล เพื่อให้กู้คืนต่อจากขั้นตอนล่าสุดที่เสร็จแล้วได้หลังเกิดการขัดข้อง
  • การออร์เคสเตรตภายนอก แบบ Temporal, Airflow, AWS Step Functions เพิ่มทั้งตัว orchestrator กลางและที่เก็บข้อมูล ทำให้ความซับซ้อนสูงขึ้น
  • สถาปัตยกรรมบน Postgres ให้แอปพลิเคชันเซิร์ฟเวอร์ polling ตารางเวิร์กโฟลว์และบันทึกผลลัพธ์ของแต่ละขั้นตอนโดยตรง เพื่อให้กู้คืนได้
  • หลายเซิร์ฟเวอร์ป้องกันการรันซ้ำด้วย lock และ integrity constraint พร้อมรับมือปัญหาด้านการขยายระบบ ความพร้อมใช้งาน และการสังเกตการณ์ด้วยแนวทางของ Postgres
  • Postgres เดียวสามารถขยายแนวตั้งเพื่อรองรับ เวิร์กโฟลว์หลายหมื่นรายการต่อวินาที และยังใช้ประโยชน์จากการทำ replication, multi-AZ และการวิเคราะห์ด้วย SQL ได้โดยตรง

โมเดลพื้นฐานของเวิร์กโฟลว์แบบทนทาน

  • เวิร์กโฟลว์แบบทนทาน คือแนวทางที่บันทึกความคืบหน้าระหว่างการทำงานของโปรแกรมเป็น checkpoint ลงฐานข้อมูลเป็นระยะ เพื่อให้กู้คืนต่อจากขั้นตอนล่าสุดที่เสร็จสมบูรณ์ได้หลังการขัดข้องหรือความล้มเหลว
  • สามารถมองได้เหมือนการเซฟและโหลดเกมวิดีโอ ที่คอย “บันทึก” ความคืบหน้าของโปรแกรมเป็นระยะ และ “โหลด” กลับจาก checkpoint ล่าสุดหลังเกิดการขัดข้อง
  • การใช้งานที่พบได้ทั่วไปคือระบบ การออร์เคสเตรตภายนอก เช่น Temporal, Airflow และ AWS Step Functions
  • ในการออร์เคสเตรตภายนอก โปรแกรมแบบทนทานจะถูกเขียนเป็นเวิร์กโฟลว์ที่ประกอบด้วยหลายขั้นตอน และมี orchestrator กลางคอยประสานการทำงาน

วิธีทำงานของการออร์เคสเตรตภายนอก

  • เมื่อไคลเอนต์ส่งเวิร์กโฟลว์เข้ามา orchestrator จะสร้างเรคอร์ดในที่เก็บข้อมูล และ dispatch งานไปยัง worker เพื่อเริ่มรัน
  • ทุกครั้งที่ worker ทำแต่ละขั้นตอนเสร็จ จะส่งผลลัพธ์กลับไปยัง orchestrator ซึ่งจะ checkpoint เอาต์พุตนั้นลงที่เก็บข้อมูล แล้ว dispatch ขั้นตอนถัดไป
  • หาก worker ขัดข้องหรือล้มเหลว orchestrator จะ dispatch เวิร์กโฟลว์นั้นไปยัง worker ตัวอื่นอีกครั้ง และเริ่มต่อจากขั้นตอนล่าสุดที่ถูก checkpoint ไว้
  • โครงสร้างนี้เพิ่ม เซิร์ฟเวอร์ orchestrator แยกต่างหาก เข้าไปบนแนวคิดหลักที่เก็บสถานะเวิร์กโฟลว์ในฐานข้อมูล ทำให้ระบบซับซ้อนขึ้น

สถาปัตยกรรมที่ใช้ Postgres เป็น orchestrator

  • หากแก่นของเวิร์กโฟลว์แบบทนทานคือการ checkpoint สถานะโปรแกรมไว้ในฐานข้อมูล การใช้ ตัวฐานข้อมูลเอง เป็น orchestrator โดยไม่ต้องมีเซิร์ฟเวอร์แยกต่างหากจะเรียบง่ายและมีประสิทธิภาพมากกว่า
  • Postgres เป็นตัวเลือกที่เหมาะกับการสร้างเวิร์กโฟลว์แบบทนทาน เพราะมีความนิยม ขยายระบบได้ และมี ecosystem ที่สมบูรณ์
  • ในระบบเวิร์กโฟลว์แบบทนทานที่อิง Postgres แอปพลิเคชันเซิร์ฟเวอร์จะสื่อสารกับ Postgres โดยตรงเพื่อรันเวิร์กโฟลว์ โดยไม่ต้องผ่าน orchestrator กลาง
  • ไคลเอนต์จะส่งงานรันโดยสร้างรายการในตารางเวิร์กโฟลว์ของ Postgres ส่วนแอปพลิเคชันเซิร์ฟเวอร์จะ polling ตารางนั้นเพื่อ dequeue และรันเวิร์กโฟลว์
  • ระหว่างที่เซิร์ฟเวอร์รันเวิร์กโฟลว์ มันจะ checkpoint ผลลัพธ์ของแต่ละขั้นตอนไว้ใน Postgres และหากเซิร์ฟเวอร์ที่กำลังรันขัดข้องหรือทำงานล้มเหลว เซิร์ฟเวอร์ตัวอื่นจะกู้คืนเวิร์กโฟลว์จาก checkpoint ได้

เหตุผลที่ไม่จำเป็นต้องมี orchestrator กลาง

  • แอปพลิเคชันเซิร์ฟเวอร์สามารถ ประสานกันผ่าน Postgres ได้ จึงไม่จำเป็นต้องมี orchestrator กลางมาคอย dispatch เวิร์กโฟลว์ไปยัง worker
  • เซิร์ฟเวอร์สามารถช่วยกัน dequeue เวิร์กโฟลว์จากตารางใน Postgres และใช้กลไกอย่าง lock clause เพื่อให้มั่นใจว่าแต่ละเวิร์กโฟลว์จะถูก dequeue โดย worker เพียงตัวเดียวเท่านั้น
  • การ checkpoint เอาต์พุตของแต่ละขั้นตอนก็ให้ worker เขียนลง Postgres โดยตรง แทนที่จะผ่าน orchestrator
  • หากมี worker หลายตัวพยายามรันเวิร์กโฟลว์เดียวกันพร้อมกัน integrity constraint ของ Postgres จะตรวจจับงานซ้ำในจังหวะ checkpoint และทำให้ตัวที่ซ้ำต้องถอยออกไป
  • เมื่อนำ Postgres หรือฐานข้อมูลอื่นมาแทน orchestrator กลาง ปัญหาอย่างการขยายระบบ ความพร้อมใช้งาน การสังเกตการณ์ และความปลอดภัย ก็สามารถจัดการได้ด้วยแนวทาง native ของ Postgres ที่เป็นที่รู้จักดี

การขยายระบบและความพร้อมใช้งาน

  • ความสามารถในการขยายระบบและความพร้อมใช้งานของระบบเวิร์กโฟลว์แบบทนทานที่อิงฐานข้อมูลนั้น ถูกกำหนดโดย ฐานข้อมูลพื้นฐาน เป็นหลัก
  • สามารถขยายแนวนอนได้ด้วยการเพิ่ม worker server ดังนั้นขีดความสามารถสูงสุดจึงขึ้นอยู่กับว่าฐานข้อมูลประมวลผลเวิร์กโฟลว์ได้เร็วเพียงใด
  • เพราะ worker สามารถทดแทนกันได้และกู้คืนสถานะให้กันและกันได้ ระบบจึงยังคงพร้อมใช้งานตราบใดที่ฐานข้อมูลพื้นฐานยังใช้งานได้
  • เมื่อใช้ Postgres ข้อดีคือเรื่องการขยายระบบและความพร้อมใช้งานเป็นปัญหาที่ถูกศึกษาอย่างยาวนาน และมีวิธีแก้ที่แข็งแรงอยู่แล้ว
  • Postgres เซิร์ฟเวอร์เดียวสามารถขยายแนวตั้งเพื่อรองรับ เวิร์กโฟลว์หลายหมื่นรายการต่อวินาที
  • การขยายเพิ่มเติมสามารถทำได้ด้วย distributed Postgres เช่น CockroachDB หรือ Postgres แบบ sharding
  • Postgres รองรับ streaming replication ที่มี automatic failover และบริการแบบ managed ก็มักให้ multi-AZ deployment พร้อม SLA ด้าน high availability มาเป็นพื้นฐาน
  • งานวิศวกรรมและงานวิจัยที่สั่งสมมาหลายทศวรรษเพื่อการรัน Postgres ในระดับใหญ่ ยังสามารถนำมาใช้กับการดำเนินงานของเวิร์กโฟลว์แบบทนทานได้โดยตรง

การสังเกตการณ์

  • ในการรันแบบทนทานที่อิง Postgres เวิร์กโฟลว์และขั้นตอนต่าง ๆ จะถูก checkpoint ลงใน ตารางของ Postgres ดังนั้นเราจึงสแกน checkpoint เหล่านี้เพื่อติดตามเวิร์กโฟลว์แบบเรียลไทม์และแสดงภาพการรันได้
  • Postgres มีจุดแข็งตรงที่แทบทุกคำถามด้านการสังเกตการณ์ของเวิร์กโฟลว์สามารถเขียนเป็น SQL ได้
  • งานอย่างการค้นหาเวิร์กโฟลว์ทั้งหมดที่เกิดข้อผิดพลาดในช่วงหนึ่งเดือนที่ผ่านมา สามารถแสดงเป็นการกรองและวิเคราะห์ที่ซับซ้อนแบบ declarative ด้วย SQL
  • สิ่งนี้เป็นไปได้เพราะอาศัย relational model ของ Postgres และงานวิจัยด้าน query optimization ที่สั่งสมมาหลายทศวรรษ
  • ระบบจำนวนมากที่ใช้ data model ที่ง่ายกว่า เช่น key-value store ที่ orchestrator ภายนอกยอดนิยมใช้งานอยู่ ไม่สามารถรองรับการวิเคราะห์ด้วย SQL ในระดับเดียวกันได้
  • หากเก็บข้อมูลเวิร์กโฟลว์และขั้นตอนไว้ในตาราง Postgres และเพิ่ม secondary index สำหรับคำสั่งวิเคราะห์ที่ต้องการความเร็ว ก็จะได้ การสังเกตการณ์ ที่มีประสิทธิภาพสำหรับการรันแบบทนทาน

ความน่าเชื่อถือและความปลอดภัย

  • ในการรันแบบทนทานที่ใช้งาน orchestrator ภายนอก ทั้ง orchestrator และที่เก็บข้อมูลของมันต่างเป็น จุดล้มเหลวเพียงจุดเดียว
  • เนื่องจาก orchestrator และที่เก็บข้อมูลทำหน้าที่ประสานการรันเวิร์กโฟลว์โดยตรง หากตัวใดตัวหนึ่งล่ม แอปพลิเคชันทั้งหมดก็จะใช้งานไม่ได้
  • เพราะทั้งสองระบบจัดการและเก็บ checkpoint ของเวิร์กโฟลว์และขั้นตอนต่าง ๆ จึงอาจเข้าถึงข้อมูลแอปพลิเคชันที่มีความอ่อนไหว และต้องมีการ hardening การควบคุมการเข้าถึง และการตรวจสอบ audit เช่นเดียวกับโครงสร้างพื้นฐานสำคัญ
  • ในการรันแบบทนทานที่อิง Postgres จุดล้มเหลวเพียงจุดเดียวคือ Postgres เอง และข้อมูลเวิร์กโฟลว์ทั้งหมดถูกเก็บลง Postgres โดยตรงโดยไม่ต้องผ่านระบบอื่น
  • หากแอปพลิเคชันของคุณพึ่งพา Postgres อยู่แล้ว การเพิ่มการรันแบบทนทานจะไม่สร้างจุดล้มเหลวใหม่ และไม่เพิ่มพื้นผิวการโจมตีใหม่ที่ต้องปกป้อง
  • ฐานข้อมูลเป็นโครงสร้างพื้นฐานหลักอยู่แล้ว ดังนั้นแทนที่จะเพิ่มโครงสร้างพื้นฐานหลักใหม่เพื่อการ orchestration การนำฐานข้อมูลเดิมกลับมาใช้จึงสมเหตุสมผลกว่า

เรียนรู้เพิ่มเติม

1 ความคิดเห็น

 
GN⁺ 7 시간 전
ความคิดเห็นจาก Hacker News
  • absurd ของ Armin Ronacher เป็น implementation ของ durable workflow สำหรับ Postgres
    https://lucumr.pocoo.org/2025/11/3/absurd-workflows/
    https://github.com/earendil-works/absurd
    https://earendil-works.github.io/absurd/
    ยังไม่ได้ลองใช้เอง แต่ก็น่าจะคุ้มที่จะเอาไปเทียบกับตัวเลือกอื่น

    • ถ้าไม่ได้ต้องการ throughput สูงมาก ผมคิดว่า absurd กับ durable ที่เป็น implementation สาย Rust เป็นตัวเลือกที่ดีสำหรับการทำให้ ฝั่ง client เรียบง่ายมาก
      มันเบาพอที่ coding agent จะเก็บโครงสร้างทั้งหมดไว้ในหัวได้ง่าย และถ้าจำเป็นก็แค่ query ดูสถานะได้
  • ผมใช้ dbos.dev, restate.dev และ cf workflows อยู่ และใน Agents.md ของเราก็เขียนไว้แบบนี้
    Restate.dev ใช้กับการเชื่อมต่อระบบชำระเงินของ northflank เร็วกว่า cf workflows, ไม่ขึ้นกับ Cloudflare และปัญหาล่มของมัน, และ self-host ได้จึงไม่ติด vendor lock-in
    Cloudflare workflows ใช้กับงานที่ความสำคัญต่ำกว่า เช่น การสร้างรายงาน CSV/PDF เพราะราคาถูกมาก
    DBOS.dev ใช้กับ workflow ที่ต้องการ atomic messaging ซึ่งผูกกับ Postgres transaction และต้องการความน่าเชื่อถือ/ความทนทาน 100% เช่น การเติม materialized row หรือการส่งอีเมล/พุชที่สำคัญถึงร้านค้า
    DBOS กับ Restate ภายนอกดูคล้ายกัน แต่ Restate ต้องมี “orchestrator” กลาง จึงมีทั้งข้อดีข้อเสีย และทำให้สร้างร่วมกับเซิร์ฟเวอร์เลส worker ของ cf/vercel ได้ง่ายขึ้น
    อีกทั้งยังมี VirtualObject จึงเป็นโอเพนซอร์สทางเลือกที่ดีแบบไม่ติด vendor lock-in สำหรับ DurableObject แบบ single-thread ของ Cloudflare
    จุดที่ DBOS เด่นเป็นพิเศษมีสองอย่าง 1) สามารถทำ atomic messaging ได้ภายใน DB transaction เดียวกับ business logic ผ่าน dbos.enqueue_workflow ส่วนนี้มักเป็นจุดเปราะบางที่สุดของหลายวิธีแก้ปัญหา ดังนั้นถ้าจัดการให้เป็นแบบ atomic และ durable ได้ใน transaction เดียวกับที่รัน business logic ก็จะลดความซับซ้อนได้มาก
    2) DBOS เก็บสถานะ workflow ไว้ใน DB จึงน่าจะทำ observability dashboard ด้วย metabase/looker ได้ง่าย Restate ก็น่าจะดีถ้าสามารถเปิดเผยอินสแตนซ์ rocksdb เพื่อเชื่อมกับ metabase ได้เช่นกัน

    • สงสัยว่าจัดการเรื่อง การอัปเดตสคีมา กันอย่างไร มีการทำ migration ให้งานด้วยหรือเปล่า หรือจัดการการ deploy worker แบบเฉพาะทาง?
  • อยากรู้ความเห็นจากคนที่เคยใช้ DBOS และ Temporal
    เมื่อก่อนเคยใช้ Temporal และมันทำงานได้ค่อนข้างดี แต่เคยรู้สึกไม่สะดวกตอนออกแบบวิธีแก้เพราะข้อจำกัดเรื่องขนาดของ request payload หรือ event
    มันมีข้อดีตรงที่บังคับให้ทำตาม แนวปฏิบัติทางวิศวกรรมที่ดี แต่ก็ไม่อยากต้องเขียนลอจิกพิเศษตลอดเวลาแบบว่า ถ้าไฟล์ CSV ใหญ่กว่า 2MB ก็อัปขึ้น S3 ส่งลิงก์ต่อ แล้วค่อยดาวน์โหลดกลับมาอีกครั้งใน workflow
    เลยอยากรู้ว่าประสบการณ์กับ DBOS เป็นอย่างไร และถ้าเทียบกับ Temporal ในแง่ความซับซ้อนของการดูแลระบบหรือความเท่าเทียมของฟีเจอร์แล้วเป็นอย่างไรบ้าง

    • ไม่เคยใช้ DBOS แต่ใช้ Temporal ทั้งที่งานปัจจุบันและงานก่อนหน้า รวมแล้วประมาณ 1.5 ปี
      ที่บ้านก็เอามาใช้จัดการงาน home automation ที่ไม่ได้ไวต่อเวลามากนักด้วย latency ของ workflow ไม่ได้แย่มาก แต่คงไม่ใช้กับ trigger ที่ต้องตอบสนองทันที เช่น event ตรวจจับการเคลื่อนไหวในบ้าน ส่วน timeout ประเภทปิดอะไรบางอย่างหลังไม่มีความเคลื่อนไหวถือว่าโอเค
      ผมค่อนข้างชอบวิธีวาง REST API แบบบาง ๆ ไว้หน้า Temporal ภายใน VPC หรือ Kubernetes cluster เพราะจะได้ไม่ต้องให้ trigger แบบ event-based มาสนใจเรื่องการยืนยันตัวตนของ Temporal หรือการตรวจสถานะ workflow และยังช่วยให้ event เรียบง่ายที่สุดโดยแทบไม่มีลอจิก
      ตัวอย่างเช่น ให้ DB trigger ทำงานโดยตรงหรือใส่ event ลงคิว แล้ว handler ไปเรียก REST API แบบบาง ๆ พร้อมรายละเอียด event ที่จำเป็น REST API จะเป็นตัวตัดสินใจว่าอันนี้ควรเริ่ม workflow, ส่ง signal ไปยัง workflow เดิม หรือเพิกเฉย รูปแบบขึ้นอยู่กับกรณี แต่สำหรับผมมักใช้ SignalWithStart บ่อย หรือถ้าไม่คุ้มจะเริ่มและก็ไม่มี workflow เดิมอยู่แล้ว ก็ทิ้งไปเลย
      อีกอย่าง ฟีเจอร์ parent/child workflow มีประโยชน์มากเวลาต้อง orchestrate พฤติกรรมที่เป็นอิสระต่อกันภายในวงจรชีวิตของอ็อบเจ็กต์เดียว และชอบตรงที่ยกเลิกได้เมื่อปัจจัยภายนอกทำให้เส้นทางการดำเนินของอ็อบเจ็กต์เปลี่ยนไป
      ถ้าจะพูดแบบยาว ๆ และกำกวมหน่อย มันทรงพลังมาก ใช้งานง่ายมาก และช่วยได้มากในการย้ายลอจิกวงจรชีวิตออกไปจาก API ถ้าเก็บไว้ใน API หนี้ทางเทคนิคจะสะสมง่ายและการดูแลจะเริ่มเปราะบาง เห็นด้วยว่าการที่มันบังคับให้ทำตามแนวปฏิบัติที่ดี ดีกว่าปล่อยให้โยนลอจิกไว้ในที่ที่ดูง่ายแต่สุดท้ายกลายเป็นกับดักที่ซ่อนอยู่
    • รู้สึกว่า Temporal ซับซ้อนเกินไป แต่ก็จริงอย่างที่พูดไว้ว่า ส่วนที่ดีที่สุดคือมันบังคับให้ทำตาม แนวปฏิบัติทางวิศวกรรมที่ดี
      แต่พอลองใช้ผลิตภัณฑ์ Cloud ก็ช็อกราคา ใช้เครดิตฟรี 1,000 ดอลลาร์หมดไปก่อนจะขึ้น production เสียอีก และก็ไม่อยากรัน Temporal แบบ local เองด้วย
      ส่วนตัวคิดว่าทางที่ดีที่สุดคือเอาแค่แนวคิดจากสถาปัตยกรรมของมันมา แล้วไปทำเองบน Postgres
    • เพิ่งออก แนวทางใช้ external storage เพื่อแก้ปัญหา payload ขนาดใหญ่
      ยังไม่ถึงกับชอบ 100% มันให้ความรู้สึกเหมือนของที่เติมเข้ามาทีหลังมากกว่าจะเป็นส่วนแกน และยังเป็น release ระยะแรก ๆ อยู่ แต่ตอนนี้ก็ถือว่าแก้ปัญหาได้แล้วในทางปฏิบัติ
    • ผมดูแล Temporal deployment แบบ on-premise ขนาดใหญ่ บัญชีนี้เป็นบัญชีชั่วคราวเพราะกลัวถูกจับได้
      จากประสบการณ์ที่รันใน production มานานกว่าหนึ่งปี Temporal ออกแบบมาไม่ดี ช้า และหนักฝั่งโครงสร้างพื้นฐานแบบเกินเหตุ
      ถ้าเป็นงานที่ไม่เล็กน้อย เช่น มี event มากกว่า 200 รายการต่อ workflow และรันพร้อมกันวันละหลายร้อยตัวตลอดทั้งวัน คุณอาจเผางบโครงสร้างพื้นฐานไปหลายล้านดอลลาร์ และมันก็ยังไม่ดีอยู่ดี
      ถ้ารัน benchmark เอง ตัวเลขออกมาแย่มาก
      ทีมขายก็แย่มากจริง ๆ และดูสิ้นหวังมาก
      แต่ในมุมของนักพัฒนา SDK ค่อนข้างดี
      อย่าไปติดอยู่กับ nexus และถ้าทีมขายโทรมา ควรให้ฝ่ายกฎหมายเข้าห้องมาด้วยเสมอ
    • เราใช้ dbos กับ workflow ที่สร้างโดย AI และการประมวลผลไฟล์วิดีโอ
      ใช้เวลาสักพักกว่าจะเข้าใจว่าจะ migrate มาจาก Celery อย่างไร แต่สำหรับกรณีของเรา มันคุ้มค่า
  • Conductor OSS ก็ทำเรื่องนี้ได้ค่อนข้างดี https://docs.conductor-oss.org/devguide/ai/index.html
    https://github.com/agentspan-ai/agentspan โดยพื้นฐานแล้วคือ ชั้น Agent SDK สำหรับ Conductor ที่สามารถทำให้เอเจนต์ของ langgraph, OpenAI, vercel และ ADK มี durability และเพิ่ม orchestration ได้โดยไม่ต้องแก้โค้ด

    • ใน production ของเราใช้ Redis เป็นคิว แต่ก็เคยเห็นผู้ใช้บางรายใช้ Postgres และ MySQL เป็นคิวเหมือนกัน
  • แทนที่จะแยก data store, state machine, ข้อจำกัดของสถานะที่ถูกต้อง และลอจิกที่เปลี่ยนผ่านระหว่างสถานะที่ถูกต้องออกจากกัน ถ้าสามารถรวมสิ่งเหล่านี้เข้าเป็นเคอร์เนลบางอย่างของสถานะแอปได้ก็คงดี
    พูดตรง ๆ คือ Postgres มีความสามารถแบบนี้อยู่แล้วเยอะมาก แต่ในระดับแอปหรือผลิตภัณฑ์ ผมยังไม่เห็นภาพที่ชัดเจนว่าจะแสดงชุดสถานะที่พิสูจน์ได้ว่าแอปสามารถเปลี่ยนผ่านไปถึงได้อย่างไร และเปิดเผยสิ่งนั้นให้ฝั่งไคลเอนต์แบบที่มีประโยชน์โดยอัตโนมัติ เช่น ผู้ใช้คนนี้กดไลก์โพสต์นี้ได้ แต่แก้ไขไม่ได้
    สำหรับผมมันดูคล้าย colored Petri net แต่ยังไม่เห็นกระบวนทัศน์สถานะแอปที่เรียบง่ายเหมือนที่ฐานข้อมูลมีขอบเขตความสำเร็จที่ชัดเจน

    • Temporal.io เข้าใกล้สิ่งนี้อยู่บ้างด้วยฟีเจอร์ query, signal และ update
      แต่ก็ไม่แน่ใจว่ามันเป็นการบูรณาการแบบสมบูรณ์หรือไม่
    • มีความพยายามแบบนี้อยู่ แต่ stored procedure ยาวเป็นพันบรรทัด นี่คือฝันร้ายจริง ๆ
    • ฟังดูเหมือน convex.dev หรือ https://spacetimedb.com/ ทั้งคู่ผมไม่ได้ใช้เอง
  • เพราะ DBOS ไม่รองรับ Rust เลยไปทำเวอร์ชัน Rust ที่เล็กมากแต่คล้ายกันไว้ที่ https://github.com/tensorzero/durable
    มันค่อนข้างเสถียรและขยายได้ดี แต่แน่นอนว่าต้องระวังมากกับ การ implement SQL หวังว่าคนอ่านที่นี่จะสนใจ

    • อันนี้ก็กำลังจะเป็นโอเพนซอร์สเร็ว ๆ นี้
      https://flawless.dev/
  • เข้าใจแนวคิดนี้อย่างถ่องแท้และเห็นด้วยทั้งหมด นี่เป็นวิธีที่ยอดเยี่ยมในการใส่ความทนทานลักษณะนี้เข้าไปในระบบเวิร์กโฟลว์
    แต่ด้วยสมองแบบเกมเมอร์ ฉันก็อยากเรียกสิ่งนี้ว่า “save scumming ขนาดใหญ่” อยู่ดี หลายคนน่าจะรู้อยู่แล้วว่าแนวทางนี้ใช้ได้ผล แต่อาจยังไม่ได้เชื่อมมันเข้ากับแนวคิดวิทยาการคอมพิวเตอร์เชิงนามธรรม
    อีกกลยุทธ์หนึ่งในการเพิ่มความแข็งแกร่งคือประกอบเวิร์กโฟลว์จากการทำงานแบบ idempotent ซึ่งอาจมีประโยชน์ในกรณีที่สถานะของเวิร์กโฟลว์ใหญ่เกินกว่าจะสำรองข้อมูลได้ง่าย แทนที่จะต้องแบ็กอัป ก็แค่รันงานใหม่ตั้งแต่ต้น และทุกอย่างก่อนถึงจุดที่กลับมามีความคืบหน้าอีกครั้งก็จะกลายเป็น no-op ทั้งหมด

  • น่าทึ่งอยู่เรื่อยว่าถ้ามี Postgres อยู่ในกล่องเครื่องมือ เราจะทำอะไรได้มากแค่ไหนด้วยเครื่องมือเพียงไม่กี่ชิ้น
    ไม่นานมานี้ฉันพัฒนา distributed queue ขึ้นมา มันทำงานได้ดีมาก ผลเบนช์มาร์กก็ดี และไม่มี race condition หรือการชนกันเลย โดยใช้ SKIP LOCKED เพื่อให้ worker หลายตัวแย่งงานกันได้อย่างปลอดภัย
    ถ้าต้องการให้ worker ข้ามหลายโหนดหลีกเลี่ยงการชนกัน ก็ยังใช้ mutex ระดับเซสชัน หรือ pg advisory lock ได้ด้วย

    • ไม่ว่าอย่างไร ในกรณีแบบนี้ก็มักจะนิยมใช้ advisory lock มากกว่า เพราะถ้าถือ SELECT FOR UPDATE ไว้เยอะ ๆ มันจะสเกลได้ไม่ดี
      แก้ไข: พอกลับไปตรวจอีกที ดูเหมือนว่าตอนนี้คำแนะนำจะเปลี่ยนเป็นตรงกันข้ามแล้ว
    • แค่จองเรคคอร์ดด้วย actor ID ก็พอ
  • ใน Rails มี backend สำหรับงานที่อิงฐานข้อมูลอยู่หลายตัว แต่ตามธรรมเนียมแล้วงานหนึ่งงานควรทำแค่เรื่องเดียวและถ้าเป็นไปได้ก็ควรจบให้เร็วมาก
    เพราะแบบนี้การสร้างเวิร์กโฟลว์เลยค่อนข้างฝืน ๆ กลายเป็นว่าบรรทัดสุดท้ายของงานแรกคือต้องคิวงานที่สอง แล้วบรรทัดสุดท้ายของงานที่สองก็คิวงานที่สามต่อ
    backend งานไม่ได้แสดงสิ่งเหล่านี้เป็นเวิร์กโฟลว์ที่เชื่อมต่อกัน แต่ปฏิบัติกับมันเป็นงานอิสระ และถ้าจะพยายามทำความเข้าใจเวิร์กโฟลว์ในภาพรวมระดับสูง ก็ต้องไปอ่านหลายคลาสของงาน
    ช่วงหลัง Rails เพิ่งเพิ่มแนวคิด continuable เข้ามา ซึ่งให้ทำ checkpoint เป็นขั้น ๆ ภายในงานและกลับมาทำต่อได้ แต่ธรรมเนียมเรื่องการทำให้งานมีความรับผิดชอบเดียวก็ยังแรงอยู่ ทำให้มันยังดูแปลก ๆ หากจะใช้กับเวิร์กโฟลว์จริง
    อยากรู้ว่าคนอื่นเคยเจอปัญหาแบบนี้ไหม และหาวิธีแก้กันอย่างไร

  • นี่เป็นแพตเทิร์นที่ยอดเยี่ยม ควรทำสิ่งต่าง ๆ ให้มากที่สุดเท่าที่ทำได้ภายในฐานข้อมูล
    Spanner ภายนอกมี change streams ให้ใช้ ส่วน Spanner ภายในนั้นต่างออกไป สาเหตุหลักคือบางกรณีมีความต้องการด้านการสเกลที่รุนแรงมาก รวมถึงมีทั้งเหตุผลแบบ “ของเดิมมันก็ทำงานได้ดีอยู่แล้ว” และ “change stream ตามอำเภอใจมันน่ากลัว” ปะปนกันไป
    Spanner ภายในเปิดให้ทรานแซกชันใด ๆ ก็ได้เขียน queue entry ลงไป โดย queue ในที่นี้ก็คือ table ชนิดพิเศษที่รับรู้เรื่องเวลาแบบคร่าว ๆ คุณสามารถตั้งเวลาส่งล่วงหน้าได้ และ entry จะถูก push จาก queue ไปยัง handler โดยที่ handler เองก็สามารถเขียน DB ภายในทรานแซกชัน dequeue ได้ด้วย และยังคงได้ความสามารถในการสเกลทั้งหมดเหมือนเดิม