ส่งข้อมูลระหว่างแอพพลิเคชั่นผ่าน RabbitMQ
❓ โจทย์วันนี้จะเป็นการศึกษาหาวิธีส่งข้อมูลระหว่าง Ruby Application โดยลองนึกภาพว่าแอพตัวที่ 1ถูกสร้างมาเพื่อบันทึกข้อมูลต่างๆ เก็บไว้ และต้องการส่งข้อมูลที่บันทึกไว้ไปยังแอพตัวที่ 2 เพื่อจุดประสงค์ต่างๆ เช่น การประมวลผล (Process) หรือบันทึกเหตุการณ์ (Log)
💡 สำหรับวิธีแก้ไขโจทย์นี้เราจะใช้ RabbitMQ เป็นตัวกลางในการสื่อสารระหว่างแอพพลิเคชัน ซึ่งมีภาพการเชื่อมต่อดังแสดงในภาพด้านล่าง
แผนภาพการเชื่อมต่อระหว่าง Application กับ RabbitMQ
🌱 รูปแบบการพัฒนาเป็นดังนี้
- แอพตัวที่ 1 (Rails Application)
- โมเดล Post สำหรับเก็บข้อมูล โดยมีการดักจับเหตุการณ์
after_create
เป็น trigger ในการส่งข้อมูล - สร้างคลาส
Publisher
เพื่อทำหน้าที่ในการส่งข้อมูลไปยัง RabbitMQ โดยใช้ไลบราลี่ bunny และกำหนด channel เป็นkz.message
- เรียกใช้ Active Job ในการส่งข้อมูลผ่าน background process เพื่อให้โปรแกรมทำงานได้ราบรื่นยิ่งขึ้น
- โมเดล Post สำหรับเก็บข้อมูล โดยมีการดักจับเหตุการณ์
- แอพตัวที่ 2 (Ruby Application)
- สร้างเป็น Commandline Application ที่รับคำสั่ง
exit
เพื่อปิดโปรแกรมเพียงอย่างเดียว - สร้างคลาส
Subscriber
เพื่อรอรับข้อมูลจาก RabbitMQ โดยใช้ไลบราลี bunny เช่นเดียวกับแอพตัวที่ 1 และกำหนด channel เป็นkz.message
- เมื่อรับข้อมูลเข้าจาก RabbitMQ ก็จะทำการบันเหตุการณ์ลงในไฟล์ชื่อ
my-post.log
- สร้างเป็น Commandline Application ที่รับคำสั่ง
บันทึกโพสผ่าน Rails Application และส่งข้อมูลไปยัง RabbitMQ
Ruby Application รับข้อมูลจาก RabbitMQ และบันทึกเหตุการณ์ลงไฟล์
โค้ดตัวอย่างของ Publisher
require 'bunny'
class Publisher
class << self
def publish(chnnl, message = {})
puts "Publish message to #{chnnl} with #{message.to_json}"
stream = channel.queue("kw.#{chnnl}")
stream.publish(message.to_json)
end
def channel
@channel ||= connection.create_channel
end
def connection
@connection ||= Bunny.new.tap(&:start)
end
end
end
โค้ดตัวอย่างของ Subscriber
require 'bunny'
require 'json'
require 'logger'
@logger = Logger.new('my-post.log')
class Subscriber
class << self
def subscribe(queue, &block)
q = channel.queue(queue)
q.subscribe(manual_ack: false) do |delivery_info, properties, payload|
puts "Received #{payload}, message properties are #{properties.inspect}"
data = JSON.parse(payload)
block.call(data) if block
end
end
def channel
@channel ||= connection.create_channel
end
def connection
@connection ||= Bunny.new.tap(&:start)
end
end
end
# Start subscribe with channel name
Subscriber.subscribe("kz.message") do |data|
@logger.info("ขณะนี้มีการสร้างโพสชื่อ #{data['title']} โดย #{data['author']} เมื่อเวลา #{data['created_at']}")
end
puts("Type exit to quit")
loop do
cmd = gets.chomp
exit(0) if (cmd == 'exit')
end