مجدول المهام بلغة Rust: من مؤقت بسيط إلى job scheduler صناعي
مجدول المهام (job scheduler) هو أحد المكونات الرئيسية لأي تطبيق جاد. بلغة Rust يمكنك بناء نظام يعمل بدقة تصل إلى أجزاء من الثانية، ويستهلك حدًا أدنى من الذاكرة، ويعمل دون أعطال لسنوات. في هذه المقالة، سنشرح كيفية إنشاء مجدول مهام بلغة Rust باستخدام الوسائل القياسية والـ crates الشائعة.
لماذا كتابة مجدول بلغة Rust؟
تقدم Rust مزيجًا فريدًا من الأداء والأمان. مجدول المهام بلغة Rust:
- يضمن عدم وجود سباقات البيانات (data races) — يتحقق المترجم من ذلك في مرحلة البناء.
- يعمل بدون جامع القمامة — تأخير قابل للتنبؤ في تنفيذ المهام.
- يدعم كلاً من التنفيذ غير المتزامن ومتعدد الخيوط.
- يستهلك حدًا أدنى من الذاكرة — يمكن تشغيل آلاف المهام.
أبسط مجدول باستخدام std::thread::sleep
لنبدأ بمثال أساسي — تنفيذ مهمة بشكل دوري كل N ثانية:
use std::thread;use std::time::Duration;
fn main() { let interval = Duration::from_secs(5); loop { println!("[{}] جاري تنفيذ المهمة...", chrono::Local::now().format("%H:%M:%S")); // هنا كود المهمة الخاص بك thread::sleep(interval); }}هذا الأسلوب بسيط ولكنه غير فعال: فهو يحجب الخيط الحالي، ولا توجد إمكانية لتشغيل مهام متعددة بالتوازي.
مجدول غير متزامن باستخدام tokio
للمشاريع الحقيقية، استخدم tokio — بيئة تشغيل غير متزامنة تسمح بتشغيل آلاف المهام في خيط واحد.
use tokio::time::{interval, Duration};
#[tokio::main]async fn main() { let mut timer = interval(Duration::from_secs(10)); println!("تم تشغيل المجدول. سيتم تنفيذ المهمة كل 10 ثوانٍ."); loop { timer.tick().await; println!("[{}] جاري تنفيذ المهمة...", chrono::Local::now().format("%H:%M:%S")); // مهمة غير متزامنة: على سبيل المثال، طلب API do_work().await; }}
async fn do_work() { // محاكاة عمل مفيد tokio::time::sleep(Duration::from_millis(500)).await; println!("تم إكمال المهمة.");}المزايا: لا يحجب الخيط، يمكن تشغيل مئات من هذه المجدولات بالتوازي.
جدولة تشبه CRON باستخدام crate cron
إذا كنت بحاجة إلى جداول زمنية معقدة (مثل cron في Linux)، استخدم crate cron:
use cron::Schedule;use chrono::Utc;use std::str::FromStr;
fn main() { // كل دقيقة عند الثانية 30 let expression = "30 * * * * *"; let schedule = Schedule::from_str(expression).unwrap(); println!("عمليات التشغيل الخمس التالية:"); for datetime in schedule.upcoming(Utc).take(5) { println!(" {}", datetime); }}إليك مثال أكثر اكتمالاً مع التنفيذ الفعلي:
use cron::Schedule;use chrono::{Utc, Local};use std::thread;use std::time::Duration;use std::str::FromStr;
fn main() { // كل 15 ثانية let expression = "0/15 * * * * *"; let schedule = Schedule::from_str(expression).unwrap(); loop { let now = Utc::now(); if let Some(next) = schedule.upcoming(Utc).next() { let delay = next - now; let millis = delay.num_milliseconds().max(0) as u64; thread::sleep(Duration::from_millis(millis)); println!("[{}] مهمة مجدولة!", Local::now().format("%H:%M:%S")); // تنفيذ المهمة } else { thread::sleep(Duration::from_secs(1)); } }}مجدول صناعي مع تعدد الخيوط
للمشاريع الجادة، قم بإنشاء هيكل Scheduler