কম্পিউটার টিউটোরিয়াল

রুবি অন রেইলসে প্যারালেল টেস্টিং: রিস্ক এবং মিটিগেশন কৌশল

আপনি কি কখনো কাউকে শুনেছেন তাদের টেস্টগুলো খুব দ্রুত হচ্ছে বলে ফামির করছেন? আমি নাই।

দ্রুত টেস্ট মানে দ্রুত ফিডব্যাক। আপনি সেগুলো লোকালি রান করুন বা সিআই (CI) পাইপলাইনে, যত দ্রুত আপনার টেস্ট ফিনিশ করে, তত দ্রুত আপনি ফেইল 반응 জানাতে পারেন এবং আপনার কোড উন্নত করতে পারেন। প্রোডাক্টিভিটি গেইনের পাশাপাশি, সব জানেন স্লো টেস্ট ডেভেলপারদের রাগানো করে। কেউ তাদের ডেভেলপারদের রাগানো পছন্দ করে না।

সেটা সা হলে, লাইটনিং-ফাস্ট টেস্ট স্যুট তৈরি করা সবসময় আপনার আশা মতো সহজ নয়। ভাগ্য (\%) রেইলস ৬ একটি চমৎকার ফিচার নিয়ে এলো যাকে প্যারালেল টেস্টিং (parallel testing) বলে। এটি শুরু করা অত্যন্ত সহজ এবং আপনার টেস্ট অনেকটাই গতিবান করতে পারে। যেদবি, কিছু পিটফল (pitfalls) আছে যা ওপর নজর রাখতে হবে।

প্যারালেল টেস্টিং কী?

প্যারালেল টেস্টিং আসলে কী বোঝায়?

আপনি যখন একটি টেস্ট স্যুট রান করেন, আপনার টেস্ট রানার সাধারণত একটি সিঙ্গেল প্রসেস স্পান (spawn) করে আপনার টেস্টগুলো একে পরে একে — অথবা সিরিয়ালি (serially) এক্সিকিউট করে। একটি সিঙ্গেল টেস্ট প্রসেস একটি সিঙ্গেল সিপিইউ (CPU) কোর ব্যবহার করে। আপনি কল্পনা করতে পারেন, এই পদ্ধতিটি আধুনিক হার্ডওয়্যারের সম্পূর্ণ সুবিধা নেয় না, যেগুলো প্রায়শই ডজন ডজন সিপিইউ কোর রেখে থাকে।

আপনার ১০ কোর বিশিষ্ট একটা ফ্যান্সি ম্যাকবুক থাকতে পারে, কিন্তু দুঃখজনকভাবে, এটা আপনার টেস্টগুলো দ্রুত করবে না!

আমরা এটা পরিবর্তন করতে পারি ইনডিভিজুয়াল টেস্টগুলো একাধিক ওয়ার্কার প্রসেসে বিতরণ করে। টেস্টগুলো আর একে পরে একে রান করবে না, বরং একসাথে — প্যারালেলি (in parallel)। আপনার টেস্ট স্যুট দুই ওয়ার্কারে রান করলে এক ওয়ার্কারের চেয়ে দুগুন দ্রুত ফিনিশ হবে।

আপনার মেশিনে যত বেশি কোর থাকবে, তত বেশি ওয়ার্কার প্রসেস সম্ভব, এবং তত দ্রুত আপনার টেস্ট স্যুট ফিনিশ হবে। ধরুন আপনার টেস্টস সাধারণত ৮ মিনিট লাগে। সেম টেস্টগুলো চার ওয়ার্কার প্রসেস ব্যবহার করে রান করলে রানটাইম প্রায় ২ মিনিটে নেমে যাবে!

একটি চমৎকার ১৬ কোর মেশিনে একই জিনিস করতে চাইলে, যেখানে আমরা সোলह ওয়ার্কার স্পান করতে পারি। খুব চমৎকার!

রেইলসে প্যারালেল টেস্টিং কনফিগার করা

তাহলে আমরা সেখানে কীভাবে যাব? সম্প্রতি পর্যন্ত, আপনি থার্ড-পার্টি জেমস ব্যবহার করতে পারতেন আপনার টেস্ট স্যুট প্যারালালাইজ করার জন্য, কিন্তু রেইলস ৬ থেকে, প্যারালেল টেস্টস স্ট্যান্ডার্ড হিসেবে আসে। এটা খুব সহজ, আপনার টেস্টসে parallelize যোগ করলেই হবে:


এই কনফিগারেশন ব্যবহার করে, রেইলস আপনার মেশিনে প্রসেসরের সংখ্যা অনুযায়ী অটোমেটিক্যালি ওয়ার্কার প্রসেস স্পান করবে। রেইলস নেমস্পেসড ডাটাবেসও তৈরি করবে (যেমন database-test-0, database-test-1, ইত্যাদি) আপনার টেস্টস রান করার জন্য।

এটাই শুরু করার জন্য সব! অবশ্য, কিছু অ্যাডিশনাল কনফিগারেশন অপশন আছে আপনার প্রয়োজন হলে।

কখনো কখনো, আপনাকে প্যারালেল টেস্টসের জন্য স্পেসিফিক সেটআপ বা ক্লিনআপ করতে হতে পারে। রেইলস আপনার জন্য দুটি হুক (hooks) প্রদান করে — parallelize_setup এবং parallelize_teardown। নতুন ওয়ার্কার প্রসেস স্পান হওয়ার আগে এবং পরে এগুলো কল করা হয়:


আপনি ম্যানুয়ালি ওয়ার্কার সংখ্যাও সেট করতে পারেন:


বিকল্পভাবে, PARALLEL_WORKERS এনভায়রনমেন্ট ভেরিয়েবল ব্যবহার করে এক্সিস্টিং কনফিগারেশন ওভাররাইড করুন:


ট্রেডস (threads) ব্যবহার করে আপনার টেস্ট স্যুট প্যারালালাইজ করার অপশনও আছে।


with: :threads JRuby বা TruffleRuby ব্যবহার করার সময় ডিফল্ট অপশন। থ্রেডস থিওরিটিক্যালি কিছুটা बेटার পারফরম্যান্স দেয়। থ্রেডস প্রসেসের চেয়ে কম ওভারহেড দাবি করে, এখনের। প্র্যাকটিক্যালি, যেদবি, আমি থ্রেডস ব্যবহার করে কখনো খুব উপযোগী পাইনি, এবং আপনাকে প্রসেস-বেসড প্যারালালাইজেশনে আটকে থাকতেই ভালো।

পিটফলগুলো সাবধান থাকুন (Beware the Pitfalls)

তাহলে আপনার এক্সিস্টিং টেস্টসে parallelize যোগ করলেই অতুলনীয় স্পিডআপ পাওয়া যাবে? এটা একদম সহজ!

আপনি যদি লাকি হন, সেটি সত্য। এর চেয়ে বেশি সম্ভাবনা আপনি কিছু অপ্রত্যাশিত স্ন্যাগস (snags) ফেস করবেন যখন প্রথম بار আপনার এক্সিস্টিং টেস্ট স্যুটে প্যারালালাইজেশন যোগ করবেন। আমার কেসে নিশ্চিতভাবে সেটি হয়েছিল!

একটা জিনিস ক্লিয়ার করি। আপনি যদি মিনিটেস্ট (Minitest) এর বদলে RSpec ব্যবহার করেন, আপনি আউট অফ লাক (out of luck)। RSpec রেইলস ৬ বিল্ট-ইন প্যারালেল টেস্টিং সাপোর্ট করে না। এটা পরিবর্তন করার জন্য একটি চলমান আলোচনা আছে, কিন্তু কিছুক্ষণ ধরে কোনো সিগনিফিক্যান্ট প্রগ্রেস নেই। আপনি যদি RSpec-এ প্যারালেল টেস্ট চান, আপনার সেরা বিট (bet) থার্ড-পার্টি জেমস যেমন grosser/parallel_tests।

একটি অন্য অপ্রত্যাশিত ইস্যু যা আপনি ফেস করতে পারেন হল ছোট সংখ্যক টেস্ট প্যারালেলি রান করলে সিরিয়ালি রান করার চেয়ে স্লোওয়ার (slower) হয়। প্যারালেল টেস্ট সেটআপ করার একটি সিগনিফিক্যান্ট ওভারহেড আছে — যেমন একাধিক ডাটাবেস তৈরি করা — যা প্যারালালাইজেশন থেকে আপনি যে গেইন পেতে পারতেন সেটি এলিমিনেট করতে পারে।

আপনি ছোট সংখ্যক টেস্টের জন্য প্যারালেল টেস্ট ডিজেবল করে ভালো থাকতে পারেন। আপনি PARALLEL_WORKERS এনভায়রনমেন্ট ভেরিয়েবল ব্যবহার করে এটি করতে পারেন:


রেইলস ৭ এটা ঠিক করেছে প্যারালেল এক্সিকিউশন শুধু তখন ইনাবেল করে যখন আপনি অনেক টেস্ট এক্সিকিউট করেন। তাই আপনি যদি ইতিমধ্যে আপগ্রেড করে থাকেন, আপনি এই সমস্যা ফেস করবেন না। ডিফল্টলি, প্যারালালাইজেশন থ্রেশহোল্ড ৫০ সেট করা থাকে, কিন্তু আপনি ওভাররাইড করতে পারেন:


সबसे শেষ সমস্যা যা আমি হাইলাইট করতে চাই, সেটি আপনি সবচেয়ে বেশি ফেস করবেন, এবং এটি সবচেয়ে ইনসিডিয়াস (insidious) এবং ডিল করার কঠিন। আপনি প্যারালেল টেস্ট আপনার টেস্ট স্যুটের জন্য ইনাবেল করলে র‍্যান্ডম ফেইলার দেখতে শুরু করতে পারেন। প্যারালালাইজেশন কীভাবে এটা কARS করতে পারে বুঝতে, একটি সিম্পল টেস্ট কেস দেখি:


এটা কিছুটা বেকার হলেও, এই টেস্টটি পরিপূর্ণ। এটি ১০০% টাইম পাস করবে যতক্ষণ না এটি সিরিয়ালি রান করা হয়। প্রতিটি টেস্ট আইসোলেটেড, এবং এই টেস্টগুলো র‍্যান্ডম অর্ডারে এক্সিকিউট করলে সেগুলো ফেইল করে না। এটা পরিবর্তন হয় যখন আপনি একাধিক প্রসেস বা থ্রেড যোগ করেন মিক্সে।

টেস্টগুলো প্যারালেলি রান করলে, আপনার টেস্টগুলোর ইনডিভিজুয়াল স্টেটমেন্টস এক্সিকিউশন অর্ডার সিপিইউ শিডিউলিং (CPU scheduling) এর কারণে পরিবর্তন হতে পারে। উদাহরণে তাকিয়ে, আপনি কখনো কখনো এমন এক্সিকিউশন অর্ডার দেখবেন:


যেহেতু ওয়ার্কার ২ ফাইলটি ডিলিট করলো ওয়ার্কার ১-এর অ্যাসারশন এক্সিকিউট হওয়ার আগে, প্রথম টেস্টটি ফেইল করবে — কখনো কখনো। ইনসাল্ট টু ইনজুরি (insult to injury) যোগ করতে, একটি ভিন্ন এক্সিকিউশন অর্ডার কখনো কখনো দ্বিতীয় টেস্ট ফেইল করবে এবং প্রথমটি পাস করবে।

এই সহজ উদাহরণটি একটি ইস্যু ইলাস্ট্রেট করে যা শুধু ফাইলগুলোর সীমাবদ্ধ নয়, বরং যেকোনো সিঙ্গল্টন রিসোর্স (singleton resource) যেটি আপনার টেস্টস নন-থ্রেড-সেফ (non-thread-safe)ভাবে অ্যাক্সেস করে। ধরুন আপনি একটি রেডিস (Redis) ডাটাবেস বা ইলাস্টিকসার্চ (Elasticsearch) ইন্ডেক্সে লিখছেন। সেক্ষেত্রে, আপনি সাদৃশ্য কমপ্লিকেশনস ফেস করবেন। আরো খারাপ, সকল টেস্ট যা র‍্যান্ডম ফেইলার কARS করে সেগুলো আবিষ্কার করতে আপনাকে কিছুটা সময় লাগতে পারে — এবং সেগুলো সব ফিক্স করতে আরও বেশি সময়।

ফ্লাকি (flaky) প্যারালেল টেস্টের জন্য কোনো সিলভার বুলেট (silver bullet) নেই। সাধারণত, আপনাকে নিশ্চিত করতে হবে একাধিক টেস্ট প্রসেস রিসোর্স শেয়ার করে না। ফাইলসের জন্য, Tempfiles ব্যবহার করুন। নেমস্পেসড রিসোর্স তৈরি করতে parallelize_setup ব্যবহার করুন (যেমন রেডিস ডাটাবেস)। ইত্যাদি।

এক্সিস্টিং রেইলস টেস্টসে প্যারালেল টেস্টিং যোগ করা

মান লিন আপনি প্যারালালাইজেশন দিয়ে র‍্যান্ডম টেস্ট ফেইলারের সাথে লড়ছেন এবং সেগুলো ফিক্স করার জন্য টাইম নেই। যেদবি, আপনি প্যারালেল টেস্টিং-এর সুবিধা নিতে চান। আপনি শুধু আপনার টেস্টসের একটি সাবসেটের জন্য এটি ইনাবেল করতে পছন্দ করতে পারেন।

শুধু যেসব টেস্ট parallelize কল করে সেগুলোই প্যারালালাইজড হবে, এবং কনসার্নস (concerns) বা প্যারেন্ট ক্লাসেস ব্যবহার করে, আপনি প্যারালেল টেস্টিং আপনার টেস্ট স্যুটে এক এক টেস্ট ক্লাস করে যোগ করতে পারেন। আপনি একটি মডিউল তৈরি করতে পারেন এরকম:


এই মডিউল ইনক্লুড করা যেকোনো টেস্ট ক্লাস এখন প্যারালেলে রান করবে:


বিকল্পভাবে, আপনি একটি নতুন টেস্ট ক্লাস তৈরি করতে পারেন যেন ParallelTest:


তারপর, সেটি থেকে ইনহেরিট করুন টেস্টস যেগুলো প্যারালেলে রান করা উচিত — এবং যেগুলো সমস্যার সৃষ্টি করে সেগুলো বাদ দিন।

প্যারালেল টেস্টিং আসলে একটি ব্যান্ড-এইড (Bandaid)

প্যারালেল টেস্টিং কম প্রচেষ্টায় প্রभाৱশালী স্পিড গেইন দেয়। ভুলবেন না: এটি আপনার টেস্ট স্যুটের স্পিড উন্নত করার অন্যান্য পদ্ধতির বিকল্প নয়, বরং একটি অডিশন (addition)।

আপনি যদি খুঁজে পান আপনার টেস্ট স্যুট স্লো এবং প্রচেষ্টা দিতে পারেন, কিছু সময় খরচ করুন এটি প্রোফাইল (profile) করতে এবং স্লো হওয়ার রুট কজ (root cause/s) ঠিক করতে। প্যারালেল টেস্টিং যোগ করা একটি স্লো টেস্ট স্যুট দ্রুত করবে, কিন্তু কখনোই একটি ইতিমধ্যে ফাস্ট টেস্ট স্যুট যা প্যারালেলে রান করে তার চেয়ে ফাস্ট হবে!

সমাপন

এই পোস্টে, আমরা দেখেছি প্যারালেল টেস্টিং কী, কীভাবে আপনি সেটআপ এবং কনফিগার করতে পারেন। আপনার টেস্টগুলো দ্রুত করার একটি উপায় দরকার হলে, প্যারালেল টেস্টিং সেটি প্রদান করে।

আপনি আপনার টেস্ট স্যুটে প্যারালেল টেস্টিং যোগ করার সময় কিছু বাধা ফেস করতে পারেন। চকিত হবেন না যখন বছরের পর বছর স্ট্রেইটলি রান হওয়া টেস্টগুলো হঠাৎ ফেইল করা শুরু করে। আপনি সেগুলোর ওয়ার্কঅראউন্ড করতে পারেন আপনার টেস্ট স্যুটের একটি সাবসেটকে প্যারালালাইজ করে।

আপনি যেকোনো পদ্ধতি বেছে নিন, প্যারালেল টেস্টিং আপনার টেস্টস দ্রুত করার একটি চমৎকার টুল!

খুশি কোডিং!

P.S. আপনি যদি রুবি ম্যাজিক পোস্টগুলো প্রেস থেকে বের होतेই পড়তে চান, আমাদের রুবি ম্যাজিক নিউজলেটার সাবস্ক্রাইব করুন এবং একক পোস্টও মিস করবেন না!

রুবি অন রেইলসে প্যারালেল টেস্টিং: রিস্ক এবং মিটিগেশন কৌশল

হ্যান্স-ইয়াপ শ্নেডলিটজ (Hans-Jörg Schnedlitz)

আমাদের অতিথি লেখক হ্যান্স ভিয়েনা, অস্ট্রিয়া থেকে একজন রেইলস ইঞ্জিনিয়ার। তিনি অধিকাংশ সময় কোডিং বা কোডিং সম্পর্কে পড়তে ব্যয় করেন, এবং কখনো কখনো তার ব্লগে এ সম্পর্কে লিখেন! যখন তিনি স্ক্রিনের সামনে নন, তখন আপনি তাকে সম্ভবত বাইরে পাবেন, কোনো পর্বত চড়তে।

হ্যান্স-ইয়াপ শ্নেডলিটজ-এর সব আর্টিকেল


  1. AWS Elastic Beanstalk এবং RDS-এ Rails 6 স্মূথলি ডিপ্লয় করুন: সম্পূর্ণ গাইড

  2. HTML DOM Track src প্রপার্টি

  3. PHP-তে imagecreatetruecolor() ব্যবহার করে নতুন ট্রু-কালার ইমেজ কীভাবে তৈরি করবেন?

  4. RuboCop দিয়ে রুবি কোড কোয়ালিটি উন্নত: লিন্টিং ও অটো-ফরম্যাটিং