Publish-Subcribe Pattern on Rails
Bài đăng này đã không được cập nhật trong 7 năm
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
All rights reserved