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