Taking too long? Close loading screen.

สถาบันข้อมูลขนาดใหญ่ (องค์การมหาชน)

SCHEDULING: ตั้งเวลา run Python script บน Linux ด้วย CRON กัน !

Nov 4, 2021

หลังจากที่เพื่อน ๆ ได้เขียนโปรแกรมมาระยะนึง ก็อาจจะเกิดคำถามว่า “จะเป็นไปได้ไหมที่เราจะตั้งเวลา (schedule) ให้โปรแกรม Python ของเรานั้น ทำงานตามกำหนดเวลาโดยอัตโนมัติ” ตัวอย่างเช่น เราอาจจะเขียนโปรแกรมเพื่อดึงข้อมูลจาก API หรือทำการดึงข้อมูลจากเว็บไซต์ผ่านเทคนิค Web Scraping และต้องการที่จะตั้งเวลาให้ Python script ของเรานั้นดึงข้อมูลใหม่ทุก ๆ วัน

ในบทความนี้ เราจะพาเพื่อน ๆ ไปรู้จักและทดลองใช้ CRON เครื่องมือที่ช่วยให้เราสามารถตั้งเวลาทำงานของ Python script โดยอัตโนมัติบน Linux

สำหรับเพื่อน ๆ ที่สนใจการดึงข้อมูลจากเว็บไซต์ สามารถเข้าไปดูตัวอย่างได้จากลิงก์เหล่านี้นะคะ


CRON คืออะไร ?

  • Cron เป็นเครื่องมือบน Linux ที่ช่วยให้เราสามารถกำหนดเวลา การทำงานของ script หรือ คำสั่งต่าง ๆ ได้โดยอัตโนมัติ
  • โดยที่เราจะระบุ Cron job หรือ Cron schedule ซึ่งประกอบด้วยคำสั่งที่ต้องการกำหนดการทำงานควบคู่กับเวลาการทำงาน ภายในไฟล์ Crontab

“Cron มาจากภาษากรีก Chronos ซึ่งมีความหมายถึง เวลา”

“Crontab มาจาก Cron table จึงเปรียบเสมือน timetable หรือ ตารางเวลา”


การเขียนไฟล์ Crontab

รูปแบบกำหนดการ

การตั้งกำหนดการทำงานของคำสั่งต่าง ๆ ผ่าน Cron นั้นไม่ใช่เรื่องยาก เพียงแต่เราต้องเรียนรู้ รูปแบบการเขียนกำหนดการ ภายในไฟล์ Crontab

รูปแบบการเขียนกำหนดการภายในไฟล์ Crontab

ไฟล์ Crontab จะจัดเก็บกำหนดการทำงานของแต่ละคำสั่งไว้ในแต่ละบรรทัด โดยที่แต่ละบรรทัดจะประกอบไปด้วย fields ที่ระบุเวลาการทำงานของคำสั่งจำนวน 5 fields และตามด้วย คำสั่ง นั้น ๆ กล่าวคือ

Field ที่ 1ระบุ นาที (0 – 59) ที่คำสั่งจะทำงาน
Field ที่ 2ระบุ ชั่วโมง (0 – 23) ที่คำสั่งจะทำงาน
Field ที่ 3ระบุ วัน (1 – 31) ที่คำสั่งจะทำงาน
Field ที่ 4ระบุ เดือน (1 – 12) ที่คำสั่งจะทำงาน
Field ที่ 5ระบุ วันภายในสัปดาห์ (0 – 6) ที่คำสั่งจะทำงาน โดยเริ่มต้นที่ 0 = วันอาทิตย์ และสิ้นสุดที่ 6 = วันเสาร์
Field ที่ 6ระบุ ตัวคำสั่ง
การระบุเวลา

สำหรับ fields ที่กำหนดเวลาทั้ง 5 fields นั้น สามารถระบุเป็นค่าตัวเลข หรือ ใช้อักขระพิเศษมาช่วยในการระบุกำหนดการ ซึ่งรูปแบบที่เป็นไปได้ประกอบไปด้วย

รูปแบบที่เป็นได้การใช้งานตัวอย่างการระบุนาที
ค่าตัวเลขระบุค่าเวลาเฉพาะเจาะคง5หมายถึง นาทีที่ 5
*ระบุทุกค่าเวลาที่เป็นไปได้*หมายถึง ทุกนาที
,คั่นเพื่อระบุหลายค่าเวลา5,10หมายถึง นาทีที่ 5 และ 10
คั่นเพื่อระบุช่วงของเวลา5-10หมายถึง นาทีที่ 5,6,7,8,9 และ 10
/คั่นเพื่อระบุขั้นของเวลา*/5หมายถึง ทุก ๆ 5 นาที
ตัวอย่างกำหนดการ
5 * * * * echo helloเป็นการกำหนดให้คำสั่ง echo hello ทำงานที่นาทีที่ 5 ของทุกชั่วโมง
0 0 * * * echo helloเป็นการกำหนดให้คำสั่ง echo hello ทำงานทุกเที่ยงคืน
0 */2 * * * echo helloเป็นการกำหนดให้คำสั่ง echo hello ทำงานทุก ๆ 2 ชั่วโมงที่นาทีที่ 0

สำหรับตัวอย่างกำหนดการอื่น ๆ เพื่อน ๆ สามารถเข้ามาดูได้ที่ https://crontab.guru ซึ่งนอกจากจะมีตัวอย่างการระบุเวลาแล้ว เพื่อน ๆ ยังสามารถทดลองใส่การระบุเวลาของตนเองเพื่อตรวจว่าเป็นไปตามต้องการก่อนนำไปใช้จริงได้อีกด้วย

https://crontab.guru

LAB ตั้งเวลา run Python script บน ubuntu

หลังจากที่เราได้เรียนรู้รูปแบบการเขียนกำหนดการภายในไฟล์ Crontab กันแล้ว เราก็จะมาลองตั้งกำหนดการให้ Python script

1) ทำการจัดเตรียม python script ที่จะใช้ในการทดลองนี้ โดยจะตั้งชื่อว่า hello_task.py

from datetime import datetime
print(f"Hello @ {datetime.now()}")

หากทดลอง run script ด้วยคำสั่ง $python3 จะพบว่า เป็นการพิมพ์ข้อความ “Hello @ วันเวลา ณ ขณะนั้น” ออกมายังหน้าจอ ดังภาพตัวอย่างข้างล่าง

2) ตรวจสอบ python path และ script path เพื่อใช้ในการเขียนกำหนดการ

โดยใช้คำสั่ง $which python3 ในการช่วยค้นหา python path และ $pwd ในการช่วยแสดง path ที่อยู่ ณ ปัจจุบัน

หากทดลอง run script โดยใช้ full path ที่หามาได้ ควรได้ผลลัพธ์เฉกเช่นเดิม ดังที่แสดงในภาพตัวอย่างข้างล่าง

3) ทำการตรวจสอบว่า cron service ทำงานอยู่

โดยใช้คำสั่ง $systemctl status cron

4) เข้าสู่ crontab เพื่อทำการเพิ่มกำหนดการ

โดยใช้คำสั่ง $crontab -e

หากเป็นการแก้ไขครั้งแรก ระบบจะให้เราเลือกว่าต้องการใช้ editor ชนิดใดในการแก้ไฟล์ crontab ซึ่งเพื่อน ๆ สามารถเลือกใช้ editor ที่ถนัดได้ หากไม่แน่ใจแนะนำให้เลือกใช้ nano ซึ่งเป็น editor ที่ง่ายที่สุด โดยมีปุ่มลัดที่จำเป็นได้แก่ ctrl+o เพื่อบันทึกไฟล์ และ ctrl+x เพื่อออกจาก editor

หลังจากเลือก editor เสร็จ ระบบจะทำการเปิดไฟล์ crontab ขึ้นมา ซึ่งจะยังไม่มีกำหนดการใด ๆ เราสามารถเขียนกำหนดการใหม่เพิ่มต่อจากบรรทัดล่างสุดได้เลย

5) เขียนกำหนดการเพื่อ run python script ทุก ๆ นาที

โดยที่เราจะเพิ่มคำสั่งให้ redirect output มายังไฟล์ hello_log.txt เพื่อบันทึกผลลัพธ์การทำงาน

# m h dom mon dow command
* * * * * /usr/bin/python3 /home/nj_gbdi_test/test_scheduling/hello_task.py >> /home/nj_gbdi_test/test_scheduling/hello_log.txt

เกร็ดความรู้: ในการ redirect ผลลัพธ์ไปยังไฟล์นั้น
>” จะทำการสร้างไฟล์ใหม่หากยังไม่มี หรือเขียนทับไฟล์เดิมหากมีไฟล์ชื่อดังกล่าวอยู่แล้ว
“>>” จะทำการสร้างไฟล์ใหม่หากยังไม่มี หรือเขียนต่อจากไฟล์เดิมหากมีไฟล์ชื่อดังกล่าวอยู่แล้ว

6) ทำการตรวจสอบการทำงานของ CRON

หลังจากผ่านไป 2-3 นาที ลองตรวจสอบดูว่า cron ได้ทำการสั่งงานคำสั่งตามที่เราระบุไว้หรือไม่  โดยที่เราสามารถไปตรวจสอบดูได้ทั้งที่ syslog หรือ log file ที่เราสร้างไว้

(a) ตรวจสอบดูที่ syslog โดยใช้คำสั่ง $grep CRON /var/log/syslog

จากตัวอย่างในรูป พบว่าคำสั่งที่เราระบุในไฟล์ crontab ถูกสั่งทำงานไป 3 รอบ ห่างกันรอบละ 1 นาที

(b) ตรวจสอบดูที่ log file ที่เราสร้างไว้ (จากการ redirect output) โดยการอ่านข้อมูลภายในไฟล์ ด้วยคำสั่ง อาทิ $more hello_log.txt

จากตัวอย่างในรูป พบผลลัพธ์จากการ run script 3 รอบ ห่างกันรอบละ 1 นาที

7) [optional] ทำการปรับแต่งคำสั่งในกำหนดการ ให้ผลลัพธ์ของการทำงานในแต่รอบถูก log เก็บไว้แยกไฟล์กัน พร้อมทั้งมีการบันทึก error ที่อาจเกิดขึ้นเก็บไว้ด้วย

  • ดยการเพิ่ม prefix วันที่และเวลาให้กับ ชื่อ log file (ที่เราจะ redirect output)
  • พร้อมทั้งเพิ่มการ redirect error มายัง log file ดังกล่าว

ทั้งนี้เนื่องจาก ในการทำงานจริงนั้น ผลลัพธ์ของ script อาจมีความยาวมาก พร้อมทั้งอาจเกิดข้อผิดพลาดในขณะทำงาน การบันทึก log file แยกกันในแต่รอบการทำงานเป็นวิธีนึงที่จะช่วยให้การค้นหาข้อผิดพลาดเมื่อ script เกิด error ง่ายขึ้น

# m h dom mon dow command
* * * * * /usr/bin/python3 /hhome/nj_gbdi_test/test_scheduling/hello_task.py > /home/nj_gbdi_test/test_scheduling/`date +%Y%m%d%H%M%S`_hello_task.log 2>&1

** ผู้สนใจสามารถศึกษาข้อมูลเพิ่มเติมเกี่ยวกับ backtick (`) และ date format ได้ **

หลังจากผ่านไป 1-2 นาที หากตรวจสอบ directory ที่เก็บ log files จะพบว่า log files ถูกจัดเก็บแยกกันแล้ว โดยมีวันเวลาที่ชื่อไฟล์ระบุรอบของการทำงาน

บทสรุป

ในบทความนี้ เราก็ได้รู้จัก CRON เครื่องมือใน Linux ที่ช่วยให้เราสามารถกำหนดการทำงานของ Python script หรือคำสั่งต่าง ๆ ได้อย่างอัตโนมัติ ซึ่งวิธีการเบื้องต้นไม่ได้ยากอะไรเลย เพียงแค่เราเข้าไปแก้ไขไฟล์ Crontab และระบุกำหนดการทำงานของ script (เวลา + คำสั่ง run script) ให้ถูกต้อง

หวังว่าบทความนี้ จะมีประโยชน์ต่อผู้ที่ต้องการเริ่มต้น schedule python script รวมทั้งต่อยอดไปยังการ schedule commands อื่น ๆ กันนะคะ

References

https://en.wikipedia.org/wiki/Cron

https://www.adminschoice.com/crontab-quick-reference

เนื้อหาโดย ณัฐพัชร์ เศรษฐเสถียร
ตรวจทานโดย พีรดล สามะศิริ

Nuutthapachr Sethasathien

Data Scientist Government Big Data institute (GBDi)

Peeradon Samasiri, PhD

Project Manager and Senior Data Scientist at Government Big Data Institute (GBDi)