Receiving SQS messages with Ruby

2 min read

Recently, at work, I learned a way to handle SQS messages polled from an SQS queue in an efficient way. I will share the approach here.
# Path: app/services/football_events/receive_sqs_football_events.rb
class FootballEvents::ReceiveSQSFootballEvents
class_attribute :handlers, default: {}
attr_reader :queue_poller
IDLE_TIMEOUT = 28800 # 8 hours
QUEUE_NAME = 'football-events'
# Register a handler for a specific key
# @param key [String] the key to register the handler for
# @param handler [Class] the handler class to use
# @param option [Hash] the options to use
# @return [void]
def self.register_handler(key, handler, **option)
handlers[key] = handler
end
register_handler FootballEvents::GOAL, FootballEvents::ProcessGoalService
register_handler FootballEvents::FOUL, FootballEvents::ProcessFoulService
register_handler FootballEvents::OFFSIDE, FootballEvents::ProcessOffsideService
register_handler FootballEvents::CORNER, FootballEvents::ProcessCornerService
register_handler FootballEvents::PENALTY_KICK, FootballEvents::PrcoessPenaltyKickService
# Initialize the class
# @return [void]
def initialize
sqs_client = Aws::SQS::Client.new
queue_url = sqs_client.get_queue_url(queue_name: QUEUE_NAME).queue_url
@queue_poller = Aws::SQS::QueuePoller.new(queue_url, client: sqs_client)
end
# Poll the queue for messages
# @return [void]
def poll
@queue_poller.poll(idle_timeout: IDLE_TIMEOUT) do |message|
body = JSON.parse(message.body)
event_type = body['event_type']
options = body['options']
handler = handlers[event_type]
handler.new(**options).call
end
end
end
In the above code snippet, we have a service class FootballEvents::ReceiveSQSFootballEvents
that polls messages from an SQS queue named football-events
. The messages are then processed by the appropriate handler based on the event_type
field in the message body.
All the handlers need to implement a call
method, which is called to process the message. This allows for easy extensibility and maintainability of the codebase.
# app/services/football_events/process_goal_service.rb
class FootballEvents::ProcessGoalService < FootballEvents::BaseService
def initialize(match_id:, player_id:, time:)
@match_id = match_id
@player_id = player_id
@time = time
end
def call
# Process the goal event
end
end
# app/services/football_events/process_foul_service.rb
class FootballEvents::ProcessFoulService < FootballEvents::BaseService
def initialize(match_id:, player_id:, target_player_id:, time:)
@match_id = match_id
@player_id = player_id
@target_player_id = target_player_id
@time = time
end
def call
# Process the foul event
end
end
0
Subscribe to my newsletter
Read articles from Tony Duong directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Tony Duong
Tony Duong
I love writing beautiful code ✨