সম্ভাবনা হল, আপনি যদি রুবি কোড লিখছেন, আপনি ব্যাকগ্রাউন্ড প্রসেসিং পরিচালনা করতে সাইডিকিক ব্যবহার করছেন। আপনি যদি ActiveJob
থেকে আসছেন বা অন্য কোনো ব্যাকগ্রাউন্ড, সাথে থাকুন, কভার করা কিছু টিপস সেখানেও প্রয়োগ করা যেতে পারে।
লোকেরা বিভিন্ন ক্ষেত্রে (Sidekiq) ব্যাকগ্রাউন্ড কাজ ব্যবহার করে। কিছু ক্রাঞ্চনম্বার, কিছু ব্যবহারকারীদের কাছে স্বাগত ইমেল প্রেরণ করে এবং কিছু সময়সূচী ডেটাসিঙ্কিং। আপনার ক্ষেত্রে যাই হোক না কেন, আপনি শেষ পর্যন্ত ডুপ্লিকেট চাকরি এড়াতে প্রয়োজনে পড়তে পারেন। সদৃশ কাজের দ্বারা, আমি দুটি কাজ কল্পনা করি যেগুলি একই জিনিস করে। আসুন এটিতে একটু ডুব দেওয়া যাক।
কেন ডি-ডুপ্লিকেট চাকরি?
একটি দৃশ্যকল্প কল্পনা করুন যেখানে আপনার কাজ নিম্নলিখিত মত দেখায়:
class BookSalesWorker
include Sidekiq::Worker
def perform(book_id)
crunch_some_numbers(book_id)
upload_to_s3
end
...
end
BookSalesWorker
সবসময় একই কাজ করে — book_id
-এর উপর ভিত্তি করে একটি বইয়ের জন্য DB-কে জিজ্ঞাসা করে এবং কিছু সংখ্যা গণনা করতে সর্বশেষ বিক্রয় ডেটা নিয়ে আসে। তারপর, এটি তাদের একটি স্টোরেজ পরিষেবাতে আপলোড করে। মনে রাখবেন যে যতবার আপনার ওয়েবসাইটে abook বিক্রি হবে, আপনার এই কাজটি সারিবদ্ধ থাকবে।
এখন, আপনি যদি একবারে 100টি বিক্রি পান? আপনার কাছে এই কাজের 100টি ঠিক একই জিনিস করতে হবে। হয়তো আপনি যে সঙ্গে ভাল. আপনি এতটা S3writes সম্পর্কে চিন্তা করেন না, এবং আপনার সারিগুলি এত ভিড় নয়, তাই আপনি লোড পরিচালনা করতে পারেন। কিন্তু, "এটা কি স্কেল করে?"™️
ভাল, স্পষ্টভাবে না. আপনি যদি আরও বইয়ের জন্য আরও বেশি বিক্রি পেতে শুরু করেন, তাহলে আপনার সারি অপ্রয়োজনীয় কাজের সাথে দ্রুত স্তূপ হয়ে যাবে। যদি আপনার কাছে 100টি কাজ থাকে যা একটি একক বইয়ের জন্য একই কাজ করে, এবং আপনার কাছে 10টি বই সমান্তরালভাবে বিক্রি হয়, তাহলে আপনি এখন 1000টি কাজ আপনার সারিতে রয়েছেন, যেখানে বাস্তবে, প্রতিটি বইয়ের জন্য আপনার কাছে 10টি কাজ থাকতে পারে৷
এখন, আসুন কয়েকটি বিকল্পের মধ্য দিয়ে যাওয়া যাক কিভাবে আপনি আপনার সারি তৈরি থেকে ডুপ্লিকেট কাজগুলিকে আটকাতে পারেন৷
1. DIY উপায়
আপনি যদি বাহ্যিক নির্ভরতা এবং জটিল যুক্তির অনুরাগী না হন তবে আপনি এগিয়ে যেতে পারেন এবং আপনার কোডবেসে কিছু কাস্টম সমাধান যোগ করতে পারেন। আমি আমাদের উদাহরণগুলি প্রথম হাতে চেষ্টা করার জন্য একটি সাধারণ রেপো তৈরি করেছি। উদাহরণের প্রতিটি পদ্ধতিতে একটি লিঙ্ক থাকবে।
1.1 এক পতাকা পদ্ধতি
আপনি একটি পতাকা যোগ করতে পারেন যা সিদ্ধান্ত নেয় একটি চাকরি সারিবদ্ধ করা হবে কি না। কেউ একটি sales_enqueued_at
যোগ করতে পারে তাদের বইয়ের টেবিলে এবং এটি বজায় রাখুন। যেমন:
module BookSalesService
def schedule_with_one_flag(book)
# Check if the job was enqueued more than 10 minutes ago
if book.sales_enqueued_at < 10.minutes.ago
book.update(sales_enqueued_at: Time.current)
BookSalesWorker.perform_async(book.id)
end
end
end
এর মানে হল যে শেষ চাকরি সারিবদ্ধ হওয়ার সময় থেকে 10 মিনিট অতিবাহিত না হওয়া পর্যন্ত কোনও নতুন চাকরি সারিবদ্ধ হবে না। 10 মিনিট কেটে যাওয়ার পরে, আমরা তারপর sales_enqueued_at
আপডেট করি এবং একটি নতুন চাকরি সারিবদ্ধ করুন।
আরেকটি জিনিস যা আপনি করতে পারেন তা হল একটি পতাকা সেট করা যা একটি বুলিয়ান, যেমন crunching_sales
. আপনি crunching_sales
সেট করেছেন প্রথম কাজ সারিবদ্ধ হওয়ার আগে সত্য। তারপর, কাজ সম্পূর্ণ হলে আপনি এটি মিথ্যা সেট করুন। অন্যান্য সমস্ত চাকরি যা সময়সূচী করার চেষ্টা করে তা crunching_sales
পর্যন্ত প্রত্যাখ্যান করা হবে মিথ্যা।
আপনি তৈরি করা উদাহরণে এই পদ্ধতির চেষ্টা করতে পারেন।
1.2 দুটি পতাকা পদ্ধতি
যদি 10 মিনিটের জন্য সারিবদ্ধ থেকে কোনও কাজকে "লক করা" খুব ভীতিকর মনে হয়, কিন্তু আপনি এখনও আপনার কোডে অতিরিক্ত পতাকা দিয়ে ঠিক আছেন, তাহলে পরবর্তী পরামর্শ আপনার আগ্রহের হতে পারে৷
আপনি বিদ্যমান sales_enqueued_at
-এ আরেকটি পতাকা যোগ করতে পারেন — sales_calculated_at
তাহলে আমাদের কোড দেখতে এরকম কিছু দেখাবে:
module BookSalesService
def schedule_with_two_flags(book)
# Check if sales are being calculated right now
if book.sales_enqueued_at <= book.sales_calculated_at
book.update(sales_enqueued_at: Time.current)
BookSalesWorker.perform_async(book.id)
end
end
end
class BookSalesWorker
include Sidekiq::Worker
def perform(book_id)
crunch_some_numbers(book_id)
upload_to_s3
# New adition
book.update(sales_calculated_at: Time.current)
end
...
end
এটি চেষ্টা করার জন্য, উদাহরণ রেপোতে নির্দেশাবলী দেখুন।
এখন আমরা একটি কাজের সারিবদ্ধ হওয়া এবং শেষ হওয়ার মধ্যে সময়ের একটি অংশ নিয়ন্ত্রণ করি। সময়ের সেই অংশে কোনো চাকরি সারিবদ্ধ করা যাবে না। কাজ চলাকালীন, sales_enqueued_at
sales_calculated_at
থেকে বড় হবে . কাজ শেষ হয়ে গেলে, sales_calculated_at
sales_enqueued_at
এর চেয়ে বড় (আরও সাম্প্রতিক) হবে এবং একটি নতুন চাকরি সারিবদ্ধ হবে।
দুটি পতাকা ব্যবহার করা আকর্ষণীয় হতে পারে, তাই আপনি শেষবার দেখাতে পারেন যে এই বিক্রয় সংখ্যাগুলি UI এ আপডেট হয়েছে৷ তারপরে যে ব্যবহারকারীরা তাদের পড়েন তারা ডেটা কত সাম্প্রতিক তা সম্পর্কে ধারণা পেতে পারেন। একটি জয়-জয় পরিস্থিতি।
পতাকা যোগ করুন
প্রয়োজনের সময় এই জাতীয় সমাধানগুলি তৈরি করতে প্রলুব্ধ হতে পারে, তবে আমার কাছে এগুলি কিছুটা আনাড়ি দেখায় এবং তারা কিছু ওভারহেড যুক্ত করে। আপনার ব্যবহারের ক্ষেত্রে সহজ হলে আমি এটি ব্যবহার করার পরামর্শ দেব, কিন্তু যত তাড়াতাড়ি এটি জটিল বা উল্লেখযোগ্য প্রমাণিত হয়, আমি আপনাকে অন্য বিকল্পগুলি চেষ্টা করার জন্য অনুরোধ করব৷
ফ্ল্যাগ পদ্ধতির সাথে একটি বিশাল কনফারেন্স হল যে আপনি সেই 10 মিনিটের মধ্যে সারিবদ্ধ করার চেষ্টা করেছেন এমন সমস্ত কাজ হারাবেন। একটি বিশাল প্রো হল যে আপনি নির্ভরতা আনছেন না, এবং এটি খুব দ্রুত সারিতে থাকা কাজের সংখ্যা কমিয়ে দেবে৷
1.3 সারি অতিক্রম করা
একই কাজগুলিকে সারিবদ্ধ করা থেকে রোধ করার জন্য একটি কাস্টম লকিং মেকানিজম তৈরি করা আরেকটি পদ্ধতি যা আপনি নিতে পারেন। আমরা যে Sidekiq কিউতে আগ্রহী তা পরীক্ষা করব এবং দেখব যে চাকরি (কর্মী) ইতিমধ্যে সেখানে আছে কিনা। কোডটি এরকম কিছু দেখাবে:
module BookSalesService
def schedule_unique_across_queue(book)
queue = Sidekiq::Queue.new('default')
queue.each do |job|
return if job.klass == BookSalesWorker.to_s &&
job.args == [book.id]
end
BookSalesWorker.perform_async(book.id)
end
end
class BookSalesWorker
include Sidekiq::Worker
def perform(book_id)
crunch_some_numbers(book_id)
upload_to_s3
end
...
end
উপরের উদাহরণে আমরা 'default'
কিনা তা পরীক্ষা করছি সারিতে BookSalesWorker
এর ক্লাস নামের একটি কাজ আছে . চাকরির আর্গুমেন্ট বই আইডির সাথে মেলে কিনা তাও আমরা পরীক্ষা করছি। যদি BookSalesWorker
একই বুক আইডি সহ চাকরিটি সারিতে রয়েছে, আমরা তাড়াতাড়ি ফিরে আসব এবং অন্যটির সময়সূচী করব না।
মনে রাখবেন যে আপনি যদি খুব দ্রুত কাজের সময়সূচী করেন তবে তাদের মধ্যে কিছু নির্ধারিত হতে পারে কারণ সারিটি খালি রয়েছে। স্থানীয়ভাবে এটির সাথে পরীক্ষা করার সময় সঠিক জিনিসটি আমার সাথে ঘটেছিল:
100.times { BookSalesService.schedule_unique_across_queue(book) }
আপনি উদাহরণ রেপোতে এটি ব্যবহার করে দেখতে পারেন।
এই পদ্ধতির ভাল জিনিস হল যে আপনার যদি প্রয়োজন হয় তবে আপনি একটি বিদ্যমান চাকরি অনুসন্ধান করতে সমস্ত সারি অতিক্রম করতে পারেন। সমস্যাটি হল যে আপনার সারি খালি থাকলে এবং আপনি সেগুলির অনেকগুলিকে একবারে শিডিউল করে থাকলে আপনি এখনও সদৃশ কাজ পেতে পারেন৷ এছাড়াও, আপনি একটি সময়সূচী করার আগে সারিতে থাকা সমস্ত কাজের মধ্য দিয়ে সম্ভাব্যভাবে অতিক্রম করছেন, যাতে এটির আকারের উপর নির্ভর করে ব্যয়বহুল হতে পারে আপনার সারি।
2. Sidekiq Enterprise
এ আপগ্রেড করা হচ্ছেযদি আপনার বা আপনার প্রতিষ্ঠানের কাছে কিছু টাকা পড়ে থাকে, তাহলে আপনি Sidekiq-এর এন্টারপ্রাইজ সংস্করণে আপগ্রেড করতে পারেন। এটি প্রতি মাসে $179 থেকে শুরু হয় এবং এটিতে একটি দুর্দান্ত বৈশিষ্ট্য রয়েছে যা আপনাকে ডুপ্লিকেট কাজগুলি এড়াতে সহায়তা করে৷ দুর্ভাগ্যবশত, আমার কাছে SidekiqEnterprise নেই, কিন্তু আমি বিশ্বাস করি যে তাদের ডকুমেন্টেশন যথেষ্ট। আপনি সহজেই নিম্নলিখিত কোড সহ অনন্য (নন-ডুপ্লিকেটেড) কাজ পেতে পারেন:
class BookSalesWorker
include Sidekiq::Worker
sidekiq_options unique_for: 10.minutes
def perform(book_id)
crunch_some_numbers(book_id)
upload_to_s3
end
...
end
এবং এটাই. আমরা 'ওয়ান ফ্ল্যাগ অ্যাপ্রোচ' বিভাগে যা বর্ণনা করেছি তার মতোই আপনার কাজের বাস্তবায়ন রয়েছে। কাজটি 10 মিনিটের জন্য অনন্য হবে, যার অর্থ সেই সময়ের মধ্যে একই আর্গুমেন্ট সহ অন্য কোনও কাজ নির্ধারণ করা যাবে না৷
সুন্দর ওয়ান-লাইনার, হাহ? ঠিক আছে, আপনার যদি এন্টারপ্রাইজ Sidekiq থাকে এবং আপনি এই বৈশিষ্ট্যটি সম্পর্কে জানতে পেরেছেন, আমি সত্যিই আনন্দিত যে আমি সাহায্য করেছি। আমাদের মধ্যে বেশিরভাগই এটি ব্যবহার করতে যাচ্ছি না, তাই আসুন পরবর্তী সমাধানে ঝাঁপ দেওয়া যাক।
3. sidekiq-অনন্য-জবস টু দ্য রেসকিউ
হ্যাঁ, আমি জানি আমরা একটি রত্ন উল্লেখ করতে যাচ্ছি। এবং হ্যাঁ, এতে কিছু লুয়া ফাইল রয়েছে যা কিছু লোককে বন্ধ করে দিতে পারে। কিন্তু আমার সাথে সহ্য করুন, এটা সত্যিই একটি মিষ্টি চুক্তি আপনি এটি সঙ্গে পাচ্ছেন. Sidekiq-unique-jobgem অনেক লকিং এবং অন্যান্য কনফিগারেশন বিকল্পের সাথে আসে — সম্ভবত আপনার প্রয়োজনের চেয়ে বেশি।
দ্রুত শুরু করতে, sidekiq-unique-jobs
রাখুন আপনার জেমফাইলে রত্ন, bundle
করুন এবং আপনার কর্মীকে দেখানো হিসাবে কনফিগার করুন:
class UniqueBookSalesWorker
include Sidekiq::Worker
sidekiq_options lock: :until_executed,
on_conflict: :reject
def perform(book_id)
book = Book.find(book_id)
logger.info "I am a Sidekiq Book Sales worker - I started"
sleep 2
logger.info "I am a Sidekiq Book Sales worker - I finished"
book.update(sales_calculated_at: Time.current)
book.update(crunching_sales: false)
end
end
অনেকগুলি বিকল্প আছে, কিন্তু আমি এটিকে সহজ করার এবং ব্যবহার করার সিদ্ধান্ত নিয়েছি:
sidekiq_options lock: :until_executed, on_conflict: :reject
lock: :until_executed
প্রথম UniqueBookSalesWorker
কে লক করবে এটি কার্যকর না হওয়া পর্যন্ত কাজ। সাথে on_conflict: :reject
, আমরা বলছি যে আমরা অন্য সব চাকরি চাই যেগুলি কার্যকর করার চেষ্টা করে মৃত সারিতে প্রত্যাখ্যান করা হোক। উপরের বিষয়গুলিতে আমাদের DIY উদাহরণগুলিতে আমরা যা করেছি তার অনুরূপ এখানে আমরা যা করেছি।
সেই DIY উদাহরণগুলির উপর একটি সামান্য উন্নতি হল যে আমাদের কাছে যা ঘটেছে তার এক ধরণের লগ রয়েছে। এটি দেখতে কেমন তা বোঝার জন্য, আসুন নিম্নলিখিতগুলি চেষ্টা করি:
5.times { UniqueBookSalesWorker.perform_async(Book.last.id) }
শুধুমাত্র একটি কাজ সম্পূর্ণরূপে কার্যকর হবে, এবং বাকি চারটি কাজ মৃত সারিতে পাঠানো হবে, যেখানে আপনি তাদের পুনরায় চেষ্টা করতে পারেন। এই পদ্ধতিটি আমাদের উদাহরণগুলির থেকে আলাদা যেখানে সদৃশ চাকরিগুলিকে উপেক্ষা করা হয়েছিল৷
৷লকিং এবং দ্বন্দ্ব সমাধানের ক্ষেত্রে বেছে নেওয়ার জন্য অনেকগুলি বিকল্প রয়েছে৷ আমি আপনাকে আপনার নির্দিষ্ট ব্যবহারের ক্ষেত্রে রত্নটির ডকুমেন্টেশনের সাথে পরামর্শ করার পরামর্শ দিচ্ছি৷
দারুণ অন্তর্দৃষ্টি
এই রত্নটি সম্পর্কে দুর্দান্ত জিনিসটি হল যে আপনি তালাগুলি এবং আপনার সারিতে যা পড়েছিল তার ইতিহাস দেখতে পারেন৷ আপনাকে যা করতে হবে তা হল আপনার config/routes.rb
এ নিম্নলিখিত লাইনগুলি যোগ করুন :
# config/routes.rb
require 'sidekiq_unique_jobs/web'
Rails.application.routes.draw do
mount Sidekiq::Web, at: '/sidekiq'
end
এটি মূল Sidekiq ক্লায়েন্টকে অন্তর্ভুক্ত করবে, তবে এটি আপনাকে আরও দুটি পৃষ্ঠা দেবে - একটি কাজের লকগুলির জন্য এবং অন্যটি চেঞ্জলগের জন্য৷ এটি দেখতে এইরকম:
লক্ষ্য করুন কিভাবে আমাদের দুটি নতুন পৃষ্ঠা আছে, "লক" এবং "চেঞ্জলগ"। বেশ চমৎকার বৈশিষ্ট্য।
আপনি উদাহরণ প্রকল্পে এই সব চেষ্টা করতে পারেন যেখানে রত্নটি ইনস্টল করা আছে এবং যাওয়ার জন্য প্রস্তুত৷
৷কেন লুয়া?
প্রথমত, আমি রত্নটির লেখক নই, তাই আমি এখানে কিছু অনুমান করছি। প্রথমবার যখন আমি রত্নটি দেখেছিলাম, আমি অবাক হয়েছিলাম:কেন রুবি মণির ভিতরে লুয়া ব্যবহার করবেন? এটি প্রথমে অদ্ভুত মনে হতে পারে, কিন্তু Redis Lua স্ক্রিপ্ট চালানো সমর্থন করে। আমি মনে করি রত্নটির লেখকের মনে এটি ছিল এবং তিনি লুয়াতে আরও চটকদার যুক্তি করতে চেয়েছিলেন।
আপনি যদি মণির রেপোতে লুয়া ফাইলগুলি দেখেন তবে সেগুলি এত জটিল নয়। সমস্ত লুয়া স্ক্রিপ্ট পরে SidekiqUniqueJobs::Script::Caller
-এ রুবি কোড থেকে কল করা হয় এখানে। অনুগ্রহ করে সোর্স কোডটি দেখুন, বিষয়গুলি কীভাবে কাজ করে তা পড়া এবং বের করা আকর্ষণীয়।
বিকল্প রত্ন
আপনি যদি ActiveJob
ব্যবহার করেন ব্যাপকভাবে, আপনি active-job-uniqueness
চেষ্টা করতে পারেন মণি ঠিক এখানে। ধারণাটি একই রকম, কিন্তু কাস্টম লুয়া স্ক্রিপ্টের পরিবর্তে, এটি Redis-এ [Redlock] টোলক আইটেম ব্যবহার করে।
এই রত্নটি ব্যবহার করে একটি অনন্য চাকরি পেতে, আপনি এইরকম একটি কাজের কল্পনা করতে পারেন:
class BookSalesJob < ActiveJob::Base
unique :until_executed
def perform
...
end
end
সিনট্যাক্স কম শব্দচয়ন কিন্তু sidekiq-unique-jobs
-এর মতো মণি আপনি যদি ActiveJob
-এর উপর নির্ভর করেন তাহলে এটি আপনার ক্ষেত্রে সমাধান করতে পারে .
চূড়ান্ত চিন্তা
আমি আশা করি আপনি আপনার অ্যাপে ডুপ্লিকেট কাজগুলি কীভাবে মোকাবেলা করবেন সে সম্পর্কে কিছু জ্ঞান অর্জন করেছেন। আমি অবশ্যই বিভিন্ন সমাধান নিয়ে গবেষণা এবং খেলার মজা পেয়েছি। আপনি যা খুঁজছিলেন তা খুঁজে না পেয়ে থাকলে, আমি আশা করি কিছু উদাহরণ আপনাকে আপনার নিজস্ব কিছু তৈরি করতে অনুপ্রাণিত করেছে।
এখানে সমস্ত কোড স্নিপেট সহ উদাহরণ প্রকল্প।
পরেরটিতে দেখা হবে, চিয়ার্স৷
৷পি.এস. আপনি যদি রুবি ম্যাজিক পোস্টগুলি প্রেস থেকে বের হওয়ার সাথে সাথে পড়তে চান তবে আমাদের রুবি ম্যাজিক নিউজলেটারে সাবস্ক্রাইব করুন এবং একটি পোস্ট মিস করবেন না!