Recently in one of our project there was a requirement to send SMS notification to users and task was to perform this functionality as background job using delayed job service. I wrote following code for sending SMS notifications to user and it was working fine. Then I just did one liner change in my code to process send_sms method asynchronously using handle_asynchronously method of delayed job and thought it will work as expected.
attr_reader :client, :sender, :recepient, :message
def initialize(recipient_ph_number, message_details)
@client = Twilio::REST::Client.new ACCOUNT_SID, AUTH_TOKEN
@sender = TWILIO_PHONE_NUMBER
@recepient = recipient_ph_number
@message = set_message(message_details).gsub(/[\s]{2,}/, ' ')
end
def send_sms
begin
client.account.messages.create(
:from => sender,
:to => "+#{recepient}",
:body => message
)
Rails.logger.info "---------Sent sms to #{recepient}--------"
rescue Twilio::REST::RequestError => e
Rails.logger.info "------#{e.message}-----"
end
end
handle_asynchronously :send_sms
After this send_sms method call was getting enqueued as background job in delayed jobs table but somehow delayed job was not able to deserialize it for processing and it was throwing well known error related to deserialization and yml parsing as follows -
Job failed to load: uninitialized constant Syck::Syck. Try to manually require the required file
And I started searching solution for above error and tried different workarounds but nothing was working. I though it is issue related to Syck and YAML parsing and searched in that direction too. At last while debugging send_sms method code I found that moving @client initialization from initialize method to send_sms as follow solves the issue.
def initialize(recipient_ph_number, message_details)
@sender = TWILIO_PHONE_NUMBER
@recepient = recipient_ph_number
@message = set_message(message_details).gsub(/[\s]{2,}/, ' ')
end
def send_sms
begin
client = Twilio::REST::Client.new ACCOUNT_SID, AUTH_TOKEN
client.account.messages.create(
:from => sender,
:to => "+#{recepient}",
:body => message
)
Rails.logger.info "---------Sent sms to #{recepient}--------"
rescue Twilio::REST::RequestError => e
Rails.logger.info "------#{e.message}-----"
end
end
handle_asynchronously :send_sms
Somehow delayed job was not able to deserialize client object with its exact state and all associations with which it was serialized. So while reading some article I found that it is recommended that either simply avoid serializing of already initialized complex objects (as in first code snippet 'client' is initialized and then serialized) along with job and instead initialize that object in method itself (as done in second code snippet) so that it will be initialized while job is deseriazlied and processed or if you still want to serialize one then you need to use some other serialization-deserialization workaround than delayed_jobs default serialization technique using YAML, so that you will not get unexpected outcome while performing operations using that complex object.
Also I found some information about similar issue with delayed job here . Though post at this link is little old but still depicts the same issue which I faced and its cause.
Let me know here if anybody knows something better and helpful in this context.