วิธีรันงานพื้นหลังใน ASP.NET Core

บทนำ

การประมวลผลไฟล์ (เช่น การส่งออกงานนำเสนอเป็น PDF) เป็นงานทั่วไปที่ทำบนเซิร์ฟเวอร์ การทำงานนี้ภายในตัวจัดการคำขอ (ในขณะที่ไคลเอนต์รอ) มีข้อเสียต่อไปนี้:

  • UI แย่. หน้าเว็บค้างและผู้ใช้ต้องรอผลลัพธ์ การรีโหลดหน้าเว็บจะยกเลิกงาน.
  • การหมดเวลาในการดำเนินการ. เราไม่สามารถรับประกันว่าการประมวลผลจะเสร็จภายในระยะเวลาที่กำหนดได้ ดังนั้นผู้ใช้อาจเห็นข้อความ “operation timeout”.
  • อัตราผ่านและความสามารถขยายตัวต่ำ. ASP.NET Core ถูกออกแบบให้ประมวลผลคำขอหลายแบบแบบอะซิงโครนัส งานที่ใช้ CPU มากและใช้เวลานานจะบล็อกเธรดและลดอัตราผ่านของเซิร์ฟเวอร์.
  • ความทนต่อข้อผิดพลาดต่ำ. หากมีสิ่งใดเกิดขึ้นระหว่างงานที่ใช้เวลานาน (เช่น ปัญหาการเชื่อมต่อ) การประมวลผลล้มเหลวและต้องเริ่มต้นใหม่ตั้งแต่ต้น.

วิธีที่ดีกว่าbetter approach คือการกำหนดงานให้ทำงานแบบอะซิงโครนัส ประมวลผลในพื้นหลัง และส่งผลลัพธ์กลับเมื่อพร้อม

ในโมเดลนี้ ผู้ใช้สามารถดูสถานะปัจจุบัน (และสามารถออกหรือรีโหลดหน้า) ทรัพยากรของเซิร์ฟเวอร์สามารถขยายได้อย่างมีประสิทธิภาพและปรับแต่งได้ตามต้องการ และสามารถใช้แนวทางการลองใหม่ได้

โซลูชันการประมวลผลพื้นหลังที่ทั่วไปประกอบด้วย:

  1. API สำหรับกำหนดเวลางาน.
  2. API สำหรับติดตามสถานะงาน.
  3. ตัวทำงานพื้นหลังเพื่อประมวลผลงานที่กำหนดเวลา.
  4. API สำหรับจัดเก็บและดึงผลลัพธ์.

ตัวอย่างงานพื้นหลัง

เพื่อสาธิตวิธีการนี้ ให้พิจารณาแอปตัวอย่าง ASP.NET Core 3.1 แอปนี้มีหน้าที่ผู้ใช้สามารถอัปโหลดงานนำเสนอและคลิก Export to PDF; งานนำเสนอนั้นจะถูกอัปโหลดและแปลงเป็น PDF โดยตัวทำงานพื้นหลัง.

เว็บแอป

เว็บแอปตัวอย่าง (โครงการ BackgroundJobDemo) มี:

  • หน้าอัปโหลดไฟล์ (Razor page “Upload”).
  • หน้าแสดงความก้าวหน้า (Razor page “Progress” พร้อมฟังก์ชัน JavaScript ไม่กี่ตัวที่ตรวจสอบและแสดงสถานะ).
  • ตัวควบคุม (JobStatusController) ที่ให้สถานะการประมวลผล (api/status/{jobId}).
  • ตัวควบคุม (JobResultController) ที่ส่งคืนไฟล์ PDF ที่ส่งออก (api/result/{id}).
  • ตัวทำงานพื้นหลังที่อิงบริการโฮสติ้งของ ASP.NET Core (ดูคลาส WorkerService).

หน้า Razor, ตัวควบคุมและตัวทำงานพื้นหลังมอบหมายการทำงานจริงผ่านอินเทอร์เฟซที่กำหนดในโครงการ BackgroundJobDemo.Common การดำเนินการที่เป็นรูปธรรมของการจัดการงานและการประมวลผลจะจัดให้ในโครงการแยก (BackgroundJobDemo.Local, BackgroundJobDemo.Aws ฯลฯ) และสามารถสลับได้ในเมธอด Startup.ConfigureServices.

เพื่อการสาธิต หน้า “Upload” ใช้การผูกโมเดลแบบบัฟเฟอร์ แต่สำหรับการอัปโหลดไฟล์ขนาดใหญ่ การสตรีมแบบไม่บัฟเฟอร์เป็น แนะนำ. สำหรับการใช้งานจริง ควรพิจารณา ด้านความปลอดภัย. หน้า “Progress” โพลล์สถานะงานที่กำหนดเวลาผ่าน JavaScript ทุกสองวินาที (ช่วงเวลานี้สามารถกำหนดค่าได้). การโพลล์เป็นวิธีทั่วไป แต่สำหรับสถานการณ์ที่ซับซ้อนยิ่งขึ้นอาจต้องการการแจ้งเตือนเรียลไทม์ผ่าน WebSockets (การสื่อสารแบบเรียลไทม์อยู่นอกขอบเขตของบทความนี้). SignalR เป็นเครื่องมือที่ง่ายแต่ทรงพลังสำหรับการสื่อสารแบบเรียลไทม์.

การโฮสต์ตัวทำงานพื้นหลังในกระบวนการของเซิร์ฟเวอร์สะดวกสำหรับแอปพลิเคชันง่าย ๆ แต่มี ข้อเสีย. วิธีที่แข็งแรงและขยายได้ดีขึ้นคือการปรับใช้ตัวทำงานในกระบวนการแยก (ดู เช่น แอปพลิเคชันคอนโซล BackgroundJobDemo.Worker).

การนำไปใช้พื้นฐาน

โครงการ BackgroundJobDemo.Local มีการนำไปใช้การจัดการงานอย่างง่ายโดยใช้ฐานข้อมูล SQLite (เส้นทางฐานข้อมูลกำหนดผ่าน LocalConfig.DbFilePath; ดู Startup.ConfigureServices). ไฟล์ที่อัปโหลดและประมวลผลจะถูกจัดเก็บในระบบไฟล์ (เส้นทางโฟลเดอร์จัดเก็บกำหนดผ่าน LocalConfig.FileStorageFolderPath; ดู Startup.ConfigureServices). เพื่อการทนต่อข้อผิดพลาดและประสิทธิภาพที่ดียิ่งขึ้นในแอปพลิเคชันจริง ควรดำเนินการกำหนดเวลางานผ่านคิวข้อความ (เช่น RabbitMQ, AWS SQS, Azure Storage Queue).

การนำไปใช้แบบกระจายบน Amazon Web Services

โครงการ BackgroundJobDemo.Aws ทำการประมวลผลงานบน Amazon Web Services และแสดงสถาปัตยกรรมแบบกระจายที่สามารถขยายแนวนอนได้ มีส่วนประกอบดังต่อไปนี้:

  • เว็บแอป — ทำงานโต้ตอบกับผู้ใช้และกำหนดเวลางานส่งออก PPTX ไปเป็น PDF เป็นต้น.
  • ตัวทำงาน — ประมวลผลการส่งออก (ในกระบวนการ, นอกกระบวนการ, หรือ AWS Lambda).
  • คิวข้อความ — จัดเก็บงานที่ต้องประมวลผล (Amazon SQS).
  • ที่เก็บไฟล์ — จัดเก็บไฟล์ที่อัปโหลดและประมวลผล (Amazon S3).
  • ที่เก็บคีย์–ค่า — ติดตามสถานะการประมวลผลงาน (Amazon DynamoDB).

สถาปัตยกรรมกระจายแบบทั่วไปอาศัย คิวข้อความ: เว็บแอปวางงานพื้นหลังลงในคิว; ตัวทำงานพื้นหลังดึงงานจากคิวและทำงานที่ต้องการ. สิ่งนี้ทำให้ส่วนประกอบแยกออกจากกันและทำให้การประมวลผลเป็นแบบอะซิงโครนัสและเชื่อถือได้. คิวรับประกันการส่งมอบและใช้ visibility timeout: เมื่อหนึ่งตัวทำงานรับข้อความ ข้อความนั้นจะซ่อนจากตัวทำงานอื่น; ตัวทำงานที่กำลังประมวลผลเท่านั้นที่ลบมันเมื่อเสร็จ. หากการประมวลผลไม่เสร็จภายใน visibility timeout (เช่น เนื่องจากความล้มเหลวหรือปัญหาเครือข่าย) ข้อความที่ไม่ได้ประมวลผลจะปรากฏอีกครั้ง.

การนำไปใช้ของเราจะใช้ Amazon Simple Queue Service (SQS) ซึ่งเป็นคิวข้อความที่จัดการแบบครบวงจรสำหรับไมโครเซอร์วิส ระบบกระจาย และแอปพลิเคชันแบบไม่มีเซิร์ฟเวอร์.

คิวข้อความออกแบบมาสำหรับข้อความขนาดเบา (เช่น ขนาดสูงสุดของข้อความ SQS คือ 256 KB) ดังนั้นข้อความควรมีเพียงรายละเอียดงานเท่านั้น ข้อมูลขนาดใหญ่ (เช่นไฟล์ที่ต้องประมวลผล) ควรจัดเก็บแยกต่างหากและอ้างอิงจากข้อความ. Amazon S3 ถูกใช้เพื่อจัดเก็บไฟล์ที่อัปโหลดและประมวลผล.

ที่เก็บคีย์–ค่าจำเป็นสำหรับการเก็บและดึงผลลัพธ์ของงานโดย ID ตัวอย่างนี้ใช้ Amazon DynamoDB, ซึ่งเป็นบริการฐานข้อมูล NoSQL ที่เร็วและยืดหยุ่น.

เพื่อเรียกใช้แอปสาธิตกับ Amazon Web Services:

  1. ในภูมิภาค AWS เดียวกัน ให้สร้างและกำหนดค่า:
    1. คิว SQS,
    2. bucket S3,
    3. ตาราง DynamoDB.
  2. เชื่อมต่อเว็บแอปกับบริการเหล่านี้โดยเรียก AddAws ใน Startup.ConfigureServices โดยระบุ URL ของคิว SQS, ชื่อ bucket S3, ชื่อ ตาราง DynamoDB, และภูมิภาค AWS.

อ้างอิง