Publish-Subcribe Pattern on Rails
Publish-Subcribe là mẫu gửi thông điệp mà publishers không gửi trực tiếp đến subscribers. Thay vào đó, gửi các thông điệp (sự kiện) mà không hề biết gì về bên nhận. Bên nhận chỉ nhận thông điệp mong muốn, mà không hề biết về thông tin bên gửi. Để thực hiện được điều đó, message brocker orevent ...
Publish-Subcribe là mẫu gửi thông điệp mà publishers không gửi trực tiếp đến subscribers. Thay vào đó, gửi các thông điệp (sự kiện) mà không hề biết gì về bên nhận.
Bên nhận chỉ nhận thông điệp mong muốn, mà không hề biết về thông tin bên gửi.
Để thực hiện được điều đó, message brocker orevent bus tiếp nhận các sự kiện sau đó chuyển tới những bên nhận mong muốn.
Một số công cụ giúp phát triển mô hình Publish-Subcribe Pattern:
- Wisper
- EventBus
- EventBGBus
- RabbitMQ
- Redis
Điểm mạnh của Publish-Subcribe Pattern là:
-
Giảm thiểu độ phình của Model/Controller
-
Giảm số lượng callbacks
Việc có nhiều callbacks giữa các models khiến cho chúng bị ràng buộc và rất khó duy trì hay phát triển.
Ví dụ một như model Entries sau:
app/models/entri.rb
class Entri field: content, type: String after_create :create_entri, :notify_followers def create_entri Post.create!(self) end def notify_followers User::NotifyFollowers.call(self) end end
app/controllers/api/v1/entries_controller.rb
class Api::V1::EntriesController < Api::V1::ApiController def create @entri = current_user.entries.build entri_params if @entri.save render_created @entri else render_unprocessable_entity @entri.errors end end end
Ta thấy model Entri có các callbacks nhưng với pub/sub, viết lại với Wisper như sau:
app/models/entri.rb
class Entri field: content, type: String end
Publisher tạo event
app/controllers/api/v1/entries_controller.rb
class Api::V1::EntriesController < Api::V1::ApiController include Wisper::Publisher def create @entri = current_user.entries.build entri_params if @entri.save publish(:entri_create, @entri) render_created(@entri) else publish(:entri_errors, @entri) render_unprocessable_entity(@entri.errors) end end # ... end
Subscribers nhận events cần thiết
app/listener/post_listener.rb
class PostListener def entri_create entri Post.create!(entri) end end
app/listener/user_listener.rb
class UserListener def entri_create entri User::NotifyFollowers.call(self) end end
Event Bus đăng kí tạo các subscribers khác nhau trong hệ thống.
config/initializers/wisper.rb
Wisper.subscribe(PostListener.new) Wisper.subscribe(UserListener.new)
Như vậy model Entri đã hoàn toàn loại bỏ các callbacks và giúp hoạt động hoàn toàn độc lập với những model khác.
Publish/Subscribe giúp cho code được sạch sẽ, dễ đọc, dễ maintain.
Ví dụ:
Publisher
app/service/financial/suggest.rb
class Financial::Suggest include Wisper::Publisher # ... def self.call(suggest) if suggest.approved? publish(:suggest_create, suggest) else publish(:suggest_decline, suggest) end end
Subscribers
app/listener/client_listener.rb
class ClientListener def suggest_create suggest Client::Charge.call(suggest) Inventory::UpdateStock.call(suggest) end def suggest_decline suggest Client::NotifyDeclinedOrder(suggest) end end
Performance
Tùy vào cách sử dụng mà có những tích cực hoặc tiêu cực: ví dụ: Khi sử dụng nhiều pub/sub để xử lý dữ liệu ở một server remote thi performance sẽ có hiệu quả không tốt, vì nó phải tải qua network. Để cải thiện về performance chúng ta có thể sử dụng Wisper, vì nó có rất nhiều adapters hỗ trợ xử lý các sự kiện không đồng bộ và thực thi nhiều threads
Tham khảo: https://www.toptal.com/ruby-on-rails/the-publish-subscribe-pattern-on-rails?utm_source=Engineering+Blog+Subscribers&utm_campaign=c760329af1-blog_post_publish_subscribe_pattern&utm_medium=email&utm_term=0_af8c2cde60-c760329af1-111583969 https://techmaster.vn/posts/24981/hoc-lap-trinh-ruby-on-rails-3