เมื่อผม Handle Exception ใน Hangfire แบบอ๊อง ๆ

Wirawat Roj
2 min readMay 31, 2021

--

สวัสดีครับ วันนี้ผมจะมาแชร์ประสบการณ์เรื่องการทำ Handle Exception ใน Background job แบบมึน ๆ โดยใช้ tools เป็น Hangfire ที่ใช้ทำ background processing สำหรับ .NET และ .NET Core นะครับ

มารู้จัก Hangfire กันก่อน

Hangfire เป็น Tools ที่ช่วยในการทำ background job processing บน .NET และ .NET Core โดยสามารถใช้งานได้ง่าย มีการทำ background process แบบต่าง ๆ ให้เลือกใช้ เช่น การ Fire-and-Forget jobs, Delayed jobs และอื่น ๆ โดย Hangfire จะมี dashboard ให้เราไว้ monitor background job ต่าง ๆ ที่ถูกรันด้วย

Hangfire Dashboard from https://www.hangfire.io/img/ui/batches.png

เมื่อเราทำเรื่อง Background process จริง ๆ แล้วจะพบว่า Background process
ต่าง ๆ นี้ก็สามารถเกิด Failed job ได้เหมือนกัน เพราะ Code การทำงานของแต่ละ Jobs ก็มาจาก Method ที่เราเขียนแล้วถูก Enqueue ด้วย Hangfire นั่นแหละ

var jobId = BackgroundJob.Enqueue(
() => Console.WriteLine("Fire-and-forget!"));

เช่น ตัวอย่าง Block code ด้านบนนี้ ก็เป็นการ Enqueue job แบบปกติ คำถามคือจะเกิดอะไรขึ้น ถ้า Background job ของเราเกิด Exception ขึ้นมา ?

เมื่อ Background job เกิด Exception !!

เมื่อ Job failed ก็จะมาอยู่ใน tab Failed

โดยปกติเมื่อ Background job เกิด Exception โดย default แล้ว hangfire จะสั่งให้ Job นั้น ๆ ทำการ re-queue ตัวเอง 10 ครั้ง หากเกิด case failed ครบทั้ง 10 ครั้ง Hangfire จะเปลี่ยน State (สถานะ) ของ Job นั้น ๆ ให้กลายเป็น FailedState ทันที

ปล. เราสามารถ config การ re-queue อัตโนมัติของ hangfire ได้โดยการ set AutomaticRetryAttribute เพิ่มได้

แล้วถ้าเราต้องการ Handle failed job ล่ะ

ตัว Hangfire เองมีสิ่งที่เรียกว่า JobFilterAttribute และ StateFilter ที่สามารถให้เราทำงานต่าง ๆ ในแต่ละ State ของ background job นั้น ๆ ได้

โดยการ Handle FailedState นั้น จะต้อง implement ตัว IElectStateFilter และ override method ดังตัวอย่าง block code ด้านล่างนี้

public void OnStateElection(ElectStateContext context)
{
var failedState = context.CandidateState as FailedState;
if (failedState != null)
{
//สามารถเขียน Logic handle ได้ตรงนี้ เช่น การส่ง email , logging
}
}

เมื่อเราสามารถ Handle FailedState ได้แบบนี้ ก็ดูไม่มีปัญหาใช่มั้ยครับ ?

ปล. เนื้อหาหลังจากนี้เป็นสิ่งที่ผมเจอตอนได้ลองทำ หากผิดพลาดประการใด สามารถแนะนำเพิ่มเติมได้นะครับ

จะเกิดอะไรขึ้น ถ้าการ handle ที่เขียนลงไปเกิด Exception ซ้ำอีกที !?

อ้างอิงจาก Topic blog นี้ ความอ๊องของผมก็คือ Logic ที่ผมเพิ่มลงไปเพื่อ handle FailedState ครั้งนี้เกิด Exception ขึ้นด้านใน method OnStateElection ข้างต้น

ทำให้ job ที่กำลังเทสรันที่ควรจะ failed และถูกย้ายไปอยู่ใน tab failed กลายเป็นการสร้าง worker มารันตัวเองซ้ำเรื่อย ๆ และไม่ยอม Failed สักที ! ซึ่งก็กินเวลาไปหลายชั่วโมงกว่าจะรู้สาเหตุว่าตัวเองพลาดอะไรครับ (ฮา)

หวังว่าทุกคนคงได้เข้าใจ Behavior ของ Hangfire ขึ้นไม่มาก ก็น้อย และผมหวังว่า blog นี้จะเป็นประโยชน์กับผู้อ่านทุกท่านนะครับ :D หากมีเนื้อหาส่วนใดผิดพลาด สามารถแนะนำเพิ่มเติมได้นะครับ ขอบคุณทุกท่านที่อ่านจนจบครับ ^^

สามารถศึกษาเพิ่มเติมได้จาก

https://www.hangfire.io/
https://docs.hangfire.io/en/latest/background-processing/dealing-with-exceptions.html (การ Set AutomaticRetryAttribute)
https://docs.hangfire.io/en/latest/extensibility/using-job-filters.html
(Using JobFilter)

Special Thanks

ขอขอบคุณ “สำนักงานส่งเสริมเศรษฐกิจดิจิทัล (depa)” และคณาจารย์ “คณะเทคโนโลยีสารสนเทศ มจธ. (SIT)” ที่ให้การสนับสนุน “ทุนเพชรพระจอมเกล้าเพื่อพัฒนาเทคโนโลยีและนวัตกรรมดิจิทัล (KMUTT-depa)” ซึ่งเป็นทุนที่มอบความรู้ ทักษะและโอกาสดี ๆ กับผมอย่างมาก~

--

--

Wirawat Roj

Software Engineer | 🍔 Always hungry | ❤️ Love Coding