ลดเวลาการเรียก API ใน Apps Script ด้วย fecthAll

Apps Script มี function UrlFetchApp.fetch() สำหรับเรียก http request ไปที่ service อื่นๆ ได้ ซึ่งสามารถนำมาใช้เรียก API ภายนอกได้เช่นกัน แต่หากเรามีข้อมูลจำนวนมาก และต้องเรียก UrlFetchApp.fetch() หลายๆ ครั้ง จะทำให้ระบบทำงานช้าและเกินข้อจำกัดของ Apps Script ไป (document ระบุไว้ว่าได้ 6 นาที) วันนี้ผมจะมาแนะนำวิธีแก้ปัญหาในกรณี้นี้กันคับ

account ที่ผมใช้งาน ตกอยู่ในกลุ่มที่มีข้อจำกัด 6 min/execution

เมื่อการเรียกทีละ request ไม่ตอบโจทย์

เรื่องเริ่มมาจากผมมีโปรเจกต์ที่มีข้อมูลชื่อโดเมน จำนวนประมาณ 1,400 รายการ ที่ต้องการดึงค่า DNS มาตรวจสอบอะไรบางอย่าง ด้วยการเรียก http request ไปที่
https://dns.google.com/resolve?name=%DOMAIN% 
โดยการแทนค่า %DOMAIN% ด้วยโดเมนที่ต้องการ และนำค่าที่ได้จาก API มาทำงานต่อ

หลังจากที่เตรียมชื่อโดเมนทั้ง 1,400 รายการลง array เรียบร้อย ก็เริ่ม process ข้อมูลใน array ทุกตัว โดยแต่ละตัวก็จะมีการเรียก UrlFetchApp.fetch() 1 ครั้ง ผลที่ได้ออกมาคือ
  • เริ่มรันตอน 2020-03-17 17:41:48.049 
  • script สามารถทำงานจนถึง record ที่ 1047
  • ที่เวลา 2020-03-17 17:49:36.137 เกิด "Script delayed (1.0 min) waiting for quota"
เวลาห่างกันประมาณ 7 นาที เข้าใจว่าเป็นเพราะติดข้อจำกัดของ Apps Script ที่รันได้ประมาณ 6 นาที

โดยปกติ หาก script ใช้เวลาจนถึงข้อจำกัด (6 นาที) ระบบจะหยุดการรัน script ทันที แต่ครั้งนี้ script ยังรันได้ต่อเพียงแต่ขึ้น Script delayed เมื่อดูจาก log สิ่งที่เกิดขึ้นคือ



delay จะเกิดขึ้นทุกนาที ในแต่ละนาที จะทำงานเพิ่มได้ 3 record ข้อมูลที่ผมไปค้นเจอ มีคำอธิบายไว้ดังนี้


ซึ่งหากปล่อยให้ script ทำงานที่อัตรา 3 record ต่อนาที กับ record ที่เหลืออีกประมาณ 360 record จะต้องใช้เวลาประมาณ 2 ชั่วโมง เพื่อให้ประมวลผมได้ครบทั้งหมด

เปลี่ยนมาเรียก request แบบ batch ด้วย fetchAll()

ทางออกหนึ่งในการแก้ปัญหานี้คือการรวมทุก request เป็นก้อน แล้วเรียก request ครั้งเดียวด้วย UrlFetchApp.fetchAll() ครับ ขั้นตอนใช้งานจะต่างออกไป คือเราจะต้องเตรียม array ซึ่งเก็บข้อมูลของ request เอาไว้ให้เรียบร้อย แล้วก็เรียก UrlFetchApp.fetchAll() โดยใส่ array ที่เตรียมไว้เป็นตัวแปร จะทำให้เราได้ผลลัพธ์จาก API ของทั้ง 1,400 record ให้ request เดียวเลย

จากการปรับวิธีเรียก request และ alogorithm ในการทำงานของ script (เปลี่ยนจากการวน loop ไล่ไปตาม array มาเป็นการประมวลผล array ทั้งก้อน) จากเดิมที่ต้องใช้เวลา 2 ชม. script ที่ปรับใหม่ใช้เวลา 17 วินาที ก็ทำงานได้เสร็จเรียบร้อย


ใครติดปัญหา script ต้องเรียก request จำนวนมากๆ ครั้นจะมาเรียก request แยกกันก็ใช้เวลานาน ลองเข้าไปดูตัวอย่าง code ในการใช้ fetchAll() ดูครับ หากนำมาปรับใช้ก็จะช่วยให้ script ทำงานได้เร็วขึ้นมากครับ

Comments

Popular posts from this blog

การใช้ Google Form ในการทำแบบประเมินความรู้ (อย่างง่าย)

การเขียน Google Apps Script เพื่อใช้งาน Custom Function

เทคนิคการใช้งาน Google Form