Đặt vấn đề:

Bạn đã từng xử lý một logic business chuyển trạng thái qua lại đơn giản hay phức tạp bao giờ chưa? Hãy tưởng tượng bạn đi mua hàng trên tiki thì quá trình từ khi bạn đặt hàng cho đến khi sản phẩm được giao tới tay bạn sẽ phải trải qua các trạng thái như thế nào? Không đơn thuần là đặt hàng cho và giỏ không đâu. Bên dưới xử lý lại là cả một bài toán xử lý khá là đau đầu.
Bạn có thể xem qua một số workflow sau và cảm nhận chủ đề bài viết này nhé!



Giờ bạn thấy công việc xử lý workflow của một feature chính phức tạp thế nào rồi chứ. Rồi giờ thì chúng ta cùng giải quyết bài toán workflow này nào!

Ý tưởng:

- Ý tưởng 1: ý tưởng này nảy ra đầu tiên mà các anh em thường nghĩ tới đó là cứ If...Else... hay Switch...Case... thôi. Đơn giản là nếu gặp trạng thái này thì xử lý thế này, gặp trạng thái kia thì xử lý thế kia.
- Ý tưởng 2: sử dụng smart enum, nếu bạn chưa từng nghe qua hay chưa tìm hiểu về smart enum thì mình sẽ đề cập tới giải pháp này ở một bài viết khác. Đại ý của ý tưởng này là giúp bạn chuyển các state enum qua lại với những ràng buộc nhất định từ đó bạn có thể handle xem ở trạng thái đó thì mình sẽ thực thi gì. Ví dụ bạn đang có trạng thái A theo workflow thì nó phải chuyển sang trạng thái C, nếu mà gọi nó chuyển qua trạng thái B thì nó sẽ văng lỗi, khi đó bạn sẽ phân tách được trường hợp chuyển từ A sang C thì làm gì, từ C sang B thì làm gì, từ A sang B thì xử lý lỗi đó thế nào.
- Ý tưởng 3: ý tưởng này phát triển từ ý tưởng 2 tạo nên, tuy nhiên mỗi bước chuyển đổi trạng thái nó sẽ phát một event hay một tín hiệu nào đó, ở đâu đó nhận được tín hiệu này sẽ xử lý thực thi logic liên quan. Nếu bạn biết đến cơ chế publish/subcribe pattern (pub/sub) thì bạn sẽ dễ dàng nắm bắt được ý tưởng này, nó kết hợp giữa cách xử lý của smart enum khi chuyển trạng thái và cách xử lý truyền nhận tín hiệu (message) của pub/sub để thực thi xử lý. Đó chính là cơ chế hoạt động của saga pattern trong bài viết này.

Giải quyết vấn đề:

Bạn cho rằng ý tưởng 1 cũng giải quyết được mà, nhưng khi bạn If...Else... các trường hợp như vậy thì với số trạng thái lớn thì bạn phải xử lý khối công việc rất lớn. Chưa kể maintain khối code đó của bạn rất khó, nếu có một thay đổi nào đó, bạn phải biết nó sẽ được thêm vào đâu và có ảnh hưởng những đoạn ElseIf... khác không? Nhanh trước mắt nhưng mà lại gây khó khăn về sau.
Với ý tưởng số 2 cũng hay đó có thể áp dụng chẳng vấn đề gì khi thêm bớt state trong workflow. Tuy nhiên nếu bạn xử lý monolithic thì chẳng vấn đề gì, khi bạn xử lý một workflow liên service trong microservice thì nó lại là lại phát sinh ra một vấn đề khác đó là khả năng xử lý bất đồng bộ và các logic phụ thuộc rất nhiều với nhau. Bạn muốn thay thế một logic thực thi trong flow thì bạn phải can thiệp vào class smart enum này.
Với Saga trong ý tưởng số 3 thì nó là một tính năng khá mạnh trong Masstransit (Một mã nguồn mở về message bus để xâc dựng các ứng dụng hướng microservice). Bình thường Masstransit đảm nhận nhiệm vụ giao tiếp giữa các service với nhau thông qua message queue (Một dữ liệu tín hiệu truyền nhận kiểu những lá thư trong hộp thư ấy). Điều đáng nói ở đây là khi bạn xử lý một logic phức tạp mà mỗi bước trong logic đó lại cần giao tiếp với service khác thì bạn cần phải fire event đi (phát tín hiệu). Và service nào đăng ký xử lý tín hiệu đó thì nó sẽ nhận nhiệm vụ chỉ xử lý khi có tín hiệu đó thôi, không quan tâm đến workflow tổng thể. Ở saga state machine nó sẽ giúp chúng ta đảm nhận việc gắn các step logic trong workflow và có cơ chế truyền nhận khi state thay đổi. Ngoài ra saga còn giúp chúng ta phát những tín hiệu xử lý thành công hay xử lý thất bại. Từ đó bạn có thể lắng nghe để xử lý các exception case (trường hợp ngoại lệ)


Ok, khi bạn đã hiểu rõ ý tưởng và cách thức hoạt động của saga rồi thì cùng mình xây dựng một ứng dụng nhỏ để hiểu rõ hơn cách chuyển đổi state và handle sự kiện nhiều service nhé.

Đầu tiên thì mình có 1 workflow đơn giản như sau:


Để implement saga state machine thì thành phần quan trọng nhất chính là MasstransitStateMachine. Class này giúp chúng ta handle logic chuyển state của toàn bộ flow trên. Đi kèm với class này đó là một model để chứa state cũng như các trường dữ liệu đi kèm với status khi chuyển đổi trạng thái. Với ví dụ demo workflow bên trên mình sẽ viết như sau
...

--
P/s: Đoạn tiếp theo là trình bày thông qua source code, nếu bạn quan tâm có thể đọc tiếp tại 
Source code: