ActiveRecord কলব্যাক হল আপনার মডেলের জীবনের বিভিন্ন পর্যায়ে কোড চালানোর একটি সহজ উপায়।
উদাহরণস্বরূপ, বলুন আপনার একটি প্রশ্নোত্তর সাইট আছে এবং আপনি সমস্ত প্রশ্নের মাধ্যমে অনুসন্ধান করতে সক্ষম হতে চান৷ প্রতিবার যখন আপনি একটি প্রশ্নে পরিবর্তন করবেন, আপনি এটিকে ইলাস্টিক সার্চের মতো কিছুতে সূচী করতে চাইবেন। ইন্ডেক্সিং করতে একটু সময় লাগে এবং জরুরী নয়, তাই আপনি Sidekiq-এর সাথে ব্যাকগ্রাউন্ডে এটি করবেন।
এটি একটি after_save
ব্যবহার করার উপযুক্ত সময় বলে মনে হচ্ছে কলব্যাক! তাই আপনার মডেলে, আপনি এরকম কিছু লিখবেন:
class Question < ActiveRecord::Base
after_save :index_for_search
# ...
private
def index_for_search
QuestionIndexerJob.perform_later(self)
end
end
class QuestionIndexerJob < ActiveJob::Base
queue_as :default
def perform(question)
# ... index the question ...
end
end
এই মহান কাজ! বা, অন্তত, এটা মনে হয়. যতক্ষণ না আপনি আরও অনেক কাজের সারিবদ্ধ হন এবং এই ত্রুটিগুলি দেখতে না পান:
2015-03-10T05:29:02.881Z 52530 TID-oupf889w4 WARN: Error while trying to deserialize arguments: Couldn't find Question with 'id'=3
অবশ্যই, Sidekiq কাজটি আবার চেষ্টা করবে এবং এটি সম্ভবত পরের বার কাজ করবে। কিন্তু এটা এখনও একটু অদ্ভুত। কেন Sidekiq আপনি এইমাত্র সংরক্ষিত প্রশ্নটি খুঁজে পাচ্ছেন না?
প্রক্রিয়াগুলির মধ্যে একটি রেস শর্ত
রেল কল after_save
রেকর্ড সংরক্ষণ করার সাথে সাথেই কলব্যাক। কিন্তু সেই রেকর্ডটি অন্যান্য ডাটাবেস সংযোগ দ্বারা দেখা যাবে না, যেমন একটি Sidekiq ব্যবহার করছে, যতক্ষণ না ডাটাবেস লেনদেন প্রতিশ্রুতিবদ্ধ, যা একটু পরে ঘটে। এর মানে এমন একটি সুযোগ রয়েছে যে Sidekiq আপনার প্রশ্নটি সংরক্ষণ করার পরে, কিন্তু আপনি এটি করার আগে খুঁজে বের করার চেষ্টা করবে। এটি আপনার রেকর্ড খুঁজে পায় না, এবং এটি বিস্ফোরিত হয়।
এই সমস্যাটি এতটাই সাধারণ যে Sidekiq-এর কাছে এটি সম্পর্কে একটি FAQ এন্ট্রি রয়েছে৷ এবং একটি সহজ সমাধান আছে।
after_save
এর পরিবর্তে :
class Question < ActiveRecord::Base
after_save :index_for_search
# ...
end
after_commit
ব্যবহার করুন :
class Question < ActiveRecord::Base
after_commit :index_for_search
# ...
end
এবং Sidekiq আপনার মডেল দেখতে না পাওয়া পর্যন্ত আপনার কাজ সারিবদ্ধ হবে না৷
সুতরাং, যখন আপনি একটি ব্যাকগ্রাউন্ড জব সারিবদ্ধ করেন বা আপনার এইমাত্র করা পরিবর্তন সম্পর্কে অন্য একটি প্রক্রিয়া জানান, after_commit
ব্যবহার করুন . যদি আপনি না করেন, তাহলে আপনি এইমাত্র স্পর্শ করা রেকর্ডটি তারা খুঁজে নাও পেতে পারেন৷
কিন্তু আরও একটি সমস্যা আছে...
ঠিক আছে, আপনি আপনার after_save
এর একগুচ্ছ পরিবর্তন করেছেন after_commit
ব্যবহার করার জন্য হুক পরিবর্তে. সবকিছু কাজ বলে মনে হচ্ছে. সবকিছু চেক করার এবং বাড়িতে যাওয়ার সময়, তাই না?
প্রথমে, আপনি আপনার পরীক্ষা চালাতে চাইবেন:
require 'test_helper'
class QuestionTest < ActiveSupport::TestCase
test "A saved question is queued for indexing" do
assert_enqueued_with(job: QuestionIndexerJob) do
Question.create(title: "Is it legal to kill a zombie?")
end
end
end
1) Failure:
QuestionTest#test_A_saved_question_is_queued_for_indexing [/Users/jweiss/Source/testapps/after_commit/test/models/question_test.rb:7]:
No enqueued job found with {:job=>QuestionIndexerJob}
উফফফ! পরীক্ষা কি চাকরির সারিবদ্ধ হওয়া উচিত ছিল না? ওখানে কি হয়েছিল?
ডিফল্টরূপে, রেল প্রতিটি টেস্ট কেসকে তার নিজস্ব ডাটাবেস লেনদেনে মোড়ক করে। এই সত্যিই জিনিস দ্রুত করতে পারেন. পরীক্ষার সময় আপনার করা সমস্ত পরিবর্তনগুলি পূর্বাবস্থায় ফিরিয়ে আনতে শুধুমাত্র একটি ডাটাবেস কমান্ড লাগে৷
কিন্তু এর মানে আপনার after_commit
কলব্যাক চলবে না। কারণ after_commit
কলব্যাক শুধুমাত্র তখনই চলে যখন সর্বোত্তম লেনদেন করা হয়েছে৷৷
যখন আপনি কল করুন save
একটি পরীক্ষার ক্ষেত্রে, এটি এখনও একটি লেনদেন করে (কম বা কম), তবে এটি দ্বিতীয়-সবচেয়ে বাইরের এখন লেনদেন। তাই আপনার after_commit
আপনি যখন আশা করেন তখন কলব্যাক চালানো হবে না। এবং আপনি তাদের ভিতরে কি ঘটছে তা পরীক্ষা করতে পারবেন না।
এই সমস্যাটিও একটি সহজ সমাধান আছে। test_after_commit
অন্তর্ভুক্ত করুন আপনার জেমফাইলে রত্ন:
group :test do
gem "test_after_commit"
end
এবং আপনার after_commit
আপনার দ্বিতীয় থেকে শেষের পরে হুক চলবে লেনদেন কমিট। যা আপনি ঘটবে বলে আশা করেছিলেন।
আপনি হয়তো ভাবছেন, "এটি অদ্ভুত। রেলের সাথে আসা একটি কলব্যাক পরীক্ষা করার জন্য আমাকে কেন একটি সম্পূর্ণ পৃথক রত্ন ব্যবহার করতে হবে? এটা কি স্বয়ংক্রিয়ভাবে হওয়া উচিত নয়?”
তুমি ঠিক বলছো. এটি অস্বাভাবিক. তবে এটি বেশি দিন অদ্ভুত থাকবে না।
একবার Rails 5 শিপ, আপনাকে test_after_commit
নিয়ে চিন্তা করতে হবে না . কারণ এই সমস্যাটি প্রায় এক মাস আগে রেলে ঠিক করা হয়েছিল।
আমার নিজের কোডে, আমি after_commit
ব্যবহার করি অনেক. আমি after_save
ব্যবহার করার চেয়ে সম্ভবত এটি বেশি ব্যবহার করি ! তবে এটি এর সমস্যা এবং অদ্ভুত প্রান্তের কেস ছাড়া আসেনি।
সংস্করণ অনুসারে সংস্করণ, যদিও, এটি আরও ভাল হচ্ছে৷৷ এবং যখন আপনি after_commit
ব্যবহার করেন সঠিক জায়গায়, অনেক অদ্ভুত, এলোমেলো ব্যতিক্রম আর ঘটবে না।