Viết chương trình Finite-state Machine với Akka

822
09-03-2018
Viết chương trình Finite-state Machine với Akka

State(S) x Event(E) -> Actions(A), State(S')

Có nghĩa khi ta đang ở trạng thái S mà có sự kiện E xảy ra, thì ta sẽ thực hiện hành động A rồi chuyển sang trạng thái S'.

Thư viện Akka của Scala từ sau phiên bản 0.10 (ra ngày 22/8/2010) có thêm tính năng FSM. Bài viết này Bizfly Cloud giới thiệu cách sử dụng tính năng này. Để hiểu bạn cần có chút kinh nghiệm Scala.

Ảnh 1.

Cách thiết kế chương trình FSM

Ta theo các bước sau:

1. Liệt kê các state có thể có

2. Tất cả state đều sử dụng chung một biến state data, cần thiết kế cấu trúc dữ liệu cho state data này

3. Ứng với từng state, liệt kê các event có thể có

4. Ứng với từng event, nêu ra action sẽ thực hiện và trạng thái tiếp theo; khi xử lí event và action, thường phải tham khảo state data

Nguyên lí thiết kế là vậy, nhưng thường ta không tự viết mã thủ công từ đầu đến cuối, mà sẽ dựa vào thư viện. Nó giúp ta một số việc:

• Kiểm tra xem event có hợp lệ hay không. Ví dụ ứng với trạng thái S nào đó chỉ có thể xảy ra sự kiện E1 hoặc E2 nào đó mà thôi.

• Tự động sinh ra event timeout. Ví dụ khi viết game cờ tướng, ta muốn khi user đang ở trạng thái phải đi nước nào đó, nếu quá 1 phút mà không đi thì sẽ bị xử thua. Dùng thư viện FSM thì có thể thiết kế để sau 1 phút nếu nó không thấy có event nào xảy ra, thì nó sẽ tự sinh ra event timeout. Ví dụ khác, khi viết game trồng trọt, ta muốn nếu sau 5 phút nếu không có sự kiện nào xảy ra đối với cái cây (ví dụ user xoá cây khỏi mảnh ruộng) thì thư viện sẽ tự động sinh ra event timeout, chương trình của ta sẽ bắt event này rồi thực hiện action là làm cho cây mọc cao to lên một chút.

Demo thư viện Akka

Akka là thư viện của Scala, được thiết kế để nhái lại thư viện OTP của Erlang. Akka muốn nhái vì OTP có nhiều tính năng cao cấp như gen_server, gen_fsm, supervisor v.v., kết hợp với tính năng hot code swapping của máy ảo BEAM của Erlang đã cho phép viết ra hệ thống có uptime lên đến 99.9999999%, nghĩa là chạy không bao giờ bị chết và có thể nâng cấp nóng không cần phải restart chương trình!

Đề bài

Ta sẽ dựa trên Akka để viết chương trình "lock" thể hiện cái khóa số ở cửa ra vào (của phòng thí nghiệm, data center v.v.), một chương trình siêu kinh điển của FSM:

• Khóa có 2 trạng thái: locked và opened

• Khi khởi tạo, khóa ở trạng thái locked và được set một chuỗi kí tự để làm mã số

• Để mở khóa user sẽ nhập mã số, mỗi lần chỉ được nhập 1 kí tự, các kí tự sẽ được lưu vào buffer

• Nếu lúc đang nhập dở dang, mà user ngưng không nhập nữa, thì sau 5 giây buffer sẽ tự động bị reset

• Sau khi nhập đúng mã số, khóa sẽ chuyển sang trạng thái opened trong 5 giây, rồi lại tự động chuyển sang trạng thái locked

Bài làm

Xin xem mã nguồn ở GitHub:

• Triết lí của Scala là kiểm tra kiểu chặt chẽ để tránh lỗi cú pháp nhảm nhí: FSM[LockState, String] cho biết trạng thái có kiểu là LockState và mỗi trạng thái sẽ được kèm theo dữ liệu có kiểu là String

• Akka có DSL cho FSM cực kì hấp dẫn: trạng thái đánh dấu bằng when, sự kiện đánh dấu bằng Event(sự kiện, dữ liệu kèm theo trạng thái), chuyển đổi trạng thái đánh dấu bằng goto, nếu không muốn chuyển trạng thái thì dùng stay, chuyển đổi dữ liệu đánh dấu bằng using, timeout đánh dấu bằng until, việc chuyển trạng thái có thể ghi nhận độc lập ở chung một chỗ bằng notifying, trạng thái bắt đầu đánh dấu bằng startWith; xem thêm mã nguồn của FSM và unit test

• startWith(Locked, "") có nghĩa trạng thái bắt đầu sẽ là Locked (ổ khoá bị khoá), user chưa nhập mã số gì hết nên dữ liệu đi kèm là chuỗi rỗng

• Timeout có nghĩa sau thời gian đánh dấu bằng until, nếu không có sự kiện nào sinh ra (do user nhập mã số), thì thư viện sẽ tự động sinh ra sự kiện StateTimeout

Để chạy thử, xin xem README.

Xem mã nguồn, bạn để ý thật ra để rõ ràng, ngoài 2 trạng thái trên, nên thêm trạng thái nữa là "đang nhập dở dang". Bạn hãy thử sửa mã nguồn để thêm trạng thái này xem sao.

>> Xem thêm: Chọn NodeJS hay Ruby?

SHARE