5 คะแนน โดย GN⁺ 2025-10-29 | 2 ความคิดเห็น | แชร์ทาง WhatsApp
  • บทความเตือนถึงข้อผิดพลาดของงาน cron ที่เกิดขึ้นระหว่างการเปลี่ยนเวลา เวลาออมแสง (DST) บนเซิร์ฟเวอร์ Linux
  • ปีละสองครั้ง จะมีการเปลี่ยนเขตเวลาใน เช้ามืดวันอาทิตย์เวลา 2:00 หรือ 3:00 น. ทำให้งาน cron อาจถูกรันซ้ำหรือข้ามการรันไป
  • มีกรณีจริงในสภาพแวดล้อม vixie-cron ที่งานช่วง 3:00~3:01 ถูก รันซ้ำ 60 ครั้งทุก ๆ 1 วินาที จนเกิดอีเมลถล่ม
  • แนวทางแก้ไขคือ ตั้งค่าเขตเวลาเป็น UTC หรือ หลีกเลี่ยงการตั้งงานในช่วงเวลาดังกล่าว และเสนอให้พัฒนา ตัวจัดตารางงานโอเพนซอร์ซ ที่ดีกว่าเดิม
  • เป็นกรณีที่ย้ำเตือนผู้ดูแลเซิร์ฟเวอร์และวิศวกร DevOps ถึง ความสำคัญของการจัดการความเสี่ยงจากการเปลี่ยนเขตเวลา

การชนกันระหว่างเวลาออมแสงกับงาน cron

  • หากตั้งงาน cron ไว้ในช่วงเช้ามืดวันอาทิตย์เวลา 2:00 หรือ 3:00 น. อาจเกิดข้อผิดพลาดในการรันโดยไม่คาดคิดเมื่อชนกับช่วงเปลี่ยน เวลาออมแสง (DST)
    • ตอนเริ่ม DST นาฬิกาจะเดินไปข้างหน้าหนึ่งชั่วโมง และตอนสิ้นสุดจะถอยหลังหนึ่งชั่วโมง ทำให้เกิด เวลาซ้ำหรือเวลาหายไป
    • ผลคือ งานในช่วงเวลานั้นอาจ ถูกรันสองครั้งหรือไม่ถูกรันเลย
  • โดยเฉพาะงานที่รันทุกสัปดาห์ในเช้ามืดวันอาทิตย์จะได้รับผลกระทบใน ช่วงเปลี่ยน DST ปีละ 2 ครั้ง
    • โดยปกติจะทำงานได้ไม่มีปัญหา แต่ในวันที่มีการเปลี่ยน DST อาจเกิด การรันซ้ำแบบผิดปกติ

กรณีจริง: ปัญหาการรันซ้ำของ vixie-cron

  • มีรายงานกรณีใน vixie-cron บน Linux ว่าเมื่อเริ่ม DST งานช่วง 3:00~3:01 ถูก รันประมาณ 60 ครั้งในช่วงห่างกัน 1 วินาที
    • แต่ละงานชนกันเองและก่อให้เกิดความวุ่นวาย เช่น อีเมลแจ้งเตือนถล่ม
    • โชคดีที่งานดังกล่าวไม่ใช่งานวิกฤต จึงไม่ทำให้ระบบเสียหาย
  • ปัญหานี้เกิดจาก โครงสร้างการจัดตารางแบบอิงเวลาอย่างเรียบง่ายของ cron
    • cron ไม่รับรู้การเปลี่ยนเขตเวลาหรือการสลับ DST แต่จะรันตามเวลาที่กำหนดไว้อย่างตรงไปตรงมา

แนวทางแก้ไขและทางเลือก

  • วิธีที่ง่ายที่สุดคือ อย่าตั้งงานในช่วงเช้ามืดวันอาทิตย์เวลา 2:00 และ 3:00 น.
    • หากหลีกเลี่ยงช่วงเวลานี้ ก็สามารถเลี่ยงปัญหาการรันซ้ำจาก DST ได้ทั้งหมด
  • อีกทางเลือกที่ได้ผลคือ ตั้งเขตเวลาของเซิร์ฟเวอร์เป็น UTC
    • UTC ไม่ใช้เวลาออมแสง จึงไม่มีการเปลี่ยนเวลา
  • ทางออกที่เป็นรากฐานกว่านั้นคือการ พัฒนาตัวจัดตารางงานที่ฉลาดกว่าเดิม
    • จำเป็นต้องมี เครื่องมือทดแทนแบบโอเพนซอร์ซ ที่มีความสามารถอย่างการป้องกันการรันซ้ำ การจำกัดเวลารัน และการรับรู้เขตเวลา

ข้อเสนอระยะยาว: ยกเลิกเวลาออมแสง

  • ผู้เขียนเสนอว่า การยกเลิก DST ในระดับนโยบายภาครัฐ คือทางออกที่ดีที่สุด
    • การเปลี่ยนเวลาปีละสองครั้งสร้างความซับซ้อนที่ไม่จำเป็นทั้งต่อการดูแลระบบและชีวิตประจำวันของผู้คน
  • อย่างไรก็ตาม ตราบใดที่ DST ยังถูกใช้อยู่ ผู้ดูแลระบบและวิศวกร DevOps ก็ต้องมีมาตรการป้องกัน
    • โดยเฉพาะกับงานที่อาศัยเวลา เช่น งานแบตช์อัตโนมัติ การสำรองข้อมูล และการหมุนเวียนล็อก ต้องจัดการอย่างระมัดระวัง

สรุป: หลักการตั้งตาราง cron อย่างปลอดภัย

  • ควร หลีกเลี่ยงงานในช่วง 2:00~3:00 น. ตอนมีการเปลี่ยน DST
  • หากเป็นไปได้ ควร ให้เซิร์ฟเวอร์ทำงานบน UTC เพื่อตัดปัญหาเรื่องเขตเวลา
  • ควรตระหนักถึงข้อจำกัดของ cron และพิจารณา ใช้เครื่องมือจัดตารางงานที่แข็งแกร่งกว่า
  • ในสภาพแวดล้อม DevOps การ จัดการเขตเวลาและทำให้ระบบอัตโนมัติน่าเชื่อถือ เป็นเรื่องสำคัญอย่างยิ่ง

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

 
semjei 2025-10-29

หลังจากที่งานที่ผมตั้งไว้ตอนตี 2 ก็เกิดปัญหาเหมือนกัน (บางครั้งรันสองรอบ บางครั้งก็ไม่รันเลย) ตั้งแต่นั้นมาผมก็เลี่ยงเวลานั้นอย่างเด็ดขาด

 
GN⁺ 2025-10-29
ความคิดเห็นใน Hacker News
  • คิดว่า DST (เวลาออมแสง) เป็นระบบที่ผิดพลาดโดยสิ้นเชิง
    มันไม่ได้แก้ปัญหาอะไรเลย แถมยังสร้างแต่ความไม่สะดวก
    แค่ยึด เวลามาตรฐาน ไว้ตลอด แล้วเลื่อนเวลาทำงานให้เร็วขึ้นหนึ่งชั่วโมงแบบช่วงหน้าร้อนก็พอ
    ตัวอย่างเช่น เปิดร้าน 6 โมงแทน 7 โมง และปิด 3 ทุ่มแทน 4 ทุ่ม
    ยังไงก็ต้องมีช่วงปรับตัวปีละสองครั้งอยู่แล้ว ดังนั้นเปลี่ยนแค่ครั้งเดียวก็พอ
    ฉันอยากเห็นแสงแดดหลังเลิกงานมากกว่า โดยเฉพาะในฤดูหนาว และไม่สนว่าแดดจะขึ้นตอนเดินทางไปทำงานหรือไม่
    เพราะยังไงก็ต้องถูกขังอยู่ในอาคาร 9 ชั่วโมง เลยอยากเห็นแสงแดดตอนที่ยังมีเวลาส่วนตัว

    • ทุกคนเกลียด DST แต่ทางเลือกที่เสนอมาก็เคยถูกลองมาแล้ว
      เช่น การทดลองใช้ DST ตลอดทั้งปีในสหรัฐฯ ช่วงปี 1973~1975
      ตอนแรกกระแสสนับสนุนสูงด้วยเหตุผลอย่างการประหยัดพลังงานและอาชญากรรมที่ลดลง
      แต่สุดท้ายกระแสตีกลับอย่างรุนแรงเพราะ อุบัติเหตุระหว่างเดินทางไปโรงเรียนในตอนเช้าที่มืด จนต้องยกเลิก
      (อ้างอิงจาก Wikipedia)
    • ก็สงสัยเหมือนกันว่าการไม่เลื่อนนาฬิกาแต่ไปเปลี่ยนเวลาทำการนั้น สุดท้ายแล้วไม่ได้ให้ผลเหมือนกันหรอกหรือ
      ฟังดูเหมือนแค่อยากเลื่อนเวลาให้มากขึ้นเท่านั้น
    • จริง ๆ แล้วไม่มีคำว่า ‘เวลาฤดูหนาว’
      มีแค่เวลามาตรฐานกับเวลาออมแสงเท่านั้น
      การพูดว่าอยากใช้ ‘เวลาฤดูหนาว’ ตลอดทั้งปีฟังดูไม่ดึงดูดทางจิตวิทยาเท่าไร
    • DST ก็เป็นเพียงวิธีแก้ปัญหาเฉพาะหน้าเพื่อให้ตรงกับ เวลาที่พระอาทิตย์ขึ้น เท่านั้น
      ผู้คนอยากเริ่มวันตอนที่ยังมีแสงอาทิตย์
      โปรแกรมเมอร์ต้องลำบากเพราะ DST ก็จริง แต่ผมคิดว่านั่นคือปัญหาที่ต้องจัดการ edge case ให้ดี
    • ข้อถกเถียงว่าจะใช้เวลามาตรฐานหรือเวลาออมแสง จริง ๆ แล้วเกิดจากการที่เรามี อิสระในการเลือกเวลาทำงาน น้อยเกินไป
      แต่ละคนมีรูปแบบการนอนต่างกัน ถ้าเลือกเวลาทำงานที่เหมาะกับตัวเองได้ ความขัดแย้งก็น่าจะลดลง
  • ตอนเคยเซ็ตอัป เซิร์ฟเวอร์ของ reddit ผมตั้งทั้งหมดเป็น เขตเวลา Arizona
    เพราะ Arizona ไม่ใช้ DST เลยต่างจากแคลิฟอร์เนียแค่ 1 ชั่วโมง
    เหตุผลที่ไม่ใช้ UTC คือเวลาอ่านล็อกนั้น ‘ลบ 1 ง่ายกว่าลบ 8’
    ตอนนี้มีทีมระดับโลกแล้วเลยเปลี่ยนมาใช้ UTC

    • เคยตัดสินใจคล้าย ๆ กัน แล้วภายหลัง ต้องมานั่งเก็บงานจนเหนื่อย
      ทางที่ดีควรตั้งทุกอย่างเป็น UTC ตั้งแต่แรก
    • แต่ก็มีความเสี่ยงว่า นิยามของเขตเวลา แบบ Arizona อาจเปลี่ยนได้
      เรื่องแบบนี้เกิดขึ้นบ่อยทั่วโลก จนสำหรับนักพัฒนาแอปปฏิทินแล้วถือเป็นงานชวนปวดหัวมาก
    • ผมไม่ชอบที่ UI ของตัวดูล็อก บังคับรูปแบบเวลา 12/24 ชั่วโมงตามภาษาของเบราว์เซอร์
      ถ้าเลือก UTC แล้ว ก็ควรสมมติว่าผู้ใช้เข้าใจรูปแบบ YYYY-MM-DD แบบ 24 ชั่วโมงได้
    • ใน Java สามารถตั้งค่าเขตเวลาเริ่มต้นได้ในระดับ JVM
      แต่ในองค์กรมีคนเปลี่ยนไปใช้ PST กันคนละแบบ จนล็อกแต่ละตัวเวลาคนละชุดและสร้างความสับสน
      สุดท้ายหัวหน้าต้องออกมาจัดการให้ ทุกแอปพลิเคชันและฐานข้อมูลใช้ PST เหมือนกันหมด
    • เวลาอ่านล็อกด้วย UTC การที่วันที่ไม่เปลี่ยนไปตามความเคยชินยังคงทำให้งงอยู่บ้าง
      แต่ตอนนี้ก็เริ่มตีความเวลา UTC ได้แบบอัตโนมัติแล้ว
  • เคยตั้งเซิร์ฟเวอร์ของบริษัทเป็น BST (เวลาอังกฤษฤดูร้อน) และใช้ cron เยอะมาก
    ทำให้เกิด ความสับสนซ้ำ ๆ ปีละสองครั้ง
    สุดท้ายก็แก้ไม่ทันจนบริษัทปิดตัวไป
    บทเรียนง่าย ๆ คือ — ใช้ UTC ซะ ถ้าไม่มีเหตุผลพิเศษ

    • ผมมี นาฬิกาเข็ม UTC วางไว้บนโต๊ะเพื่อดูประกอบเวลาอ่านล็อก
    • บางครั้งก็ต้องใช้เขตเวลาท้องถิ่นเพราะลูกค้าไม่ได้อยู่ใน UTC
      ตัวอย่างเช่น การรีเซ็ตโควตาการใช้งาน หรือ งานแบตช์สำหรับการคิดเงิน มักรันตามเวลาท้องถิ่น
    • ผมคิดว่าไม่ควรใช้ cron เอง แต่ควรใช้ ตัวจัดตารางเวลาที่เข้าใจข้อมูลและการตั้งค่าของลูกค้า จะดีกว่า
    • รายงานบางอย่างก็จำเป็นต้องอิง เวลาท้องถิ่น
      เช่น รายงาน 8 โมงเช้าในสหราชอาณาจักร ซึ่งเวลา UTC จะเปลี่ยนไปตาม DST
      เพราะฉะนั้น UTC อย่างเดียวไม่พอ และต้อง เก็บข้อมูลเขตเวลาไว้ด้วย
    • ในงานสายการเงินที่ เวลาเปิดตลาด สำคัญ UTC อย่างเดียวก็ไม่พอเช่นกัน
  • บางประเทศ (Cuba, Egypt, Lebanon) มีการ เปลี่ยน DST ตอนเที่ยงคืน
    (ลิงก์ที่เกี่ยวข้อง)

    • แปลกใจเหมือนกันที่บางที่การเปลี่ยน DST ไม่ได้เกิดตอนเที่ยงคืน
      ในบราซิล การเปลี่ยนที่ช่วง 00:00~01:00 หรือ 00:00~23:00 เคยเป็นเรื่องปกติ
    • กฎของเขตเวลามักสร้างเรื่อง คาดไม่ถึง ได้จริง ๆ
  • มีงานวิจัยที่บอกว่าในวันที่มีการปรับ DST อัตราการเสียชีวิตและการเข้าห้องฉุกเฉินพุ่งสูงขึ้น
    (บทความจาก ScienceAlert)
    นี่ไม่ใช่แค่ปัญหาเรื่อง cron เท่านั้น แต่ DST ยังเป็น ระบบที่ส่งผลเสียต่อสุขภาพ ด้วย

  • ปัญหานี้เคยถูกแก้ไว้แล้วตั้งนานใน OpenBSD และ Debian
    ในคู่มือ cron(8) ของ Debian มีคำอธิบายลอจิกสำหรับ การจัดการการเลื่อนเวลาที่น้อยกว่า 3 ชั่วโมง ตอนปรับ DST
    (ลิงก์แพตช์,
    คู่มือ,
    รายงานบั๊ก)

    • ถ้าอย่างนั้นผู้เขียนต้นฉบับก็น่าจะใช้ ดิสทริบิวชันที่ไม่ได้รวมแพตช์นี้
  • คำแนะนำคืออย่าตั้งงานไว้ตอน เที่ยงคืน (00:00)
    เพราะวันที่มักทำให้สับสนได้ง่าย ควรใช้เวลาแบบ ก้ำกึ่ง อย่าง 00:01 หรือ 01:45 แทน

    • ผมเองก็ตั้ง cron job เป็น XX:13, XX:23, XX:42 แบบนี้
      เวลาเครื่องมีอาการแปลกในช่วงเวลาหนึ่งจะได้ตามหาสาเหตุได้ง่าย
    • แทบไม่เคยมีปัญหากับ 00:00 โดยตรง
      แต่ในสภาพแวดล้อมที่ใช้เวลารูปแบบ 12 ชั่วโมงก็อาจทำให้สับสนได้
  • กว่าจะเจอปัญหาเรื่องเขตเวลาก็ไม่เคยรู้มาก่อนว่า
    ในโลกนี้มีทั้ง เวลาที่ไม่มีอยู่จริง และ เวลาที่กำกวม
    ตัวอย่างเช่น ตอนข้ามจาก 2 โมงไป 3 โมง เวลา 2:30 จะไม่มีอยู่จริง
    แต่ตอนหมุนนาฬิกากลับ เวลา 2:30 จะเกิดขึ้นสองครั้ง
    แต่ละประเทศก็ปรับ DST คนละเวลา จนมีกรณีอย่าง Chile ที่เที่ยงคืนหายไปเลย
    (บล็อกที่เกี่ยวข้อง)
    จำได้ว่าตอนเริ่มทำงานที่ Stripe ใหม่ ๆ Java กับ Ruby จัดการสถานการณ์นี้ต่างกัน จนเกิด เหตุขัดข้องติดกัน 3 ครั้ง

  • งาน cron ควร หลีกเลี่ยงการรันตรงเวลาเป๊ะ และถ้าเป็นไปได้ให้ตั้ง หลังตี 4 หรือก่อนเที่ยงคืน
    เพราะบนโครงสร้างพื้นฐานที่ใช้ร่วมกัน มักเกิดการแย่งทรัพยากรหนักในช่วงตรงชั่วโมง

    • ถ้าใช้ systemd ตัวเลือก RandomizedDelaySec ช่วยลดการชนกันได้
    • หรือจะเติมโค้ดแบบ sleep $(( $(od -N1 -tuC -An /dev/urandom) % 60 ))m ; หน้า cron command
      เพื่อเพิ่ม ดีเลย์แบบสุ่ม 0~59 นาที ก็เป็นวิธีที่ดี
  • งานตามกำหนดเวลาที่สำคัญควรออกแบบให้ idempotent (รันซ้ำได้อย่างปลอดภัย) ถ้าเป็นไปได้
    โดยเฉพาะเมื่อมีระบบคิวเข้ามาเกี่ยวข้อง การออกแบบแบบนี้คือ หัวใจสำคัญของการป้องกันปัญหา