قوائم المهام لـ Kotlin: Coroutines و KJobQueue
في التطوير الحديث باستخدام Kotlin - سواء كان تطبيق Android، أو backend على Ktor، أو خدمة مصغرة - غالبًا ما تنشأ الحاجة لتنفيذ مهام خلفية بشكل غير متزامن وبالترتيب الصحيح. تساعد قائمة المهام (job queue) في إدارة مثل هذه العمليات: تحميل الملفات، مزامنة البيانات، إرسال التحليلات، معالجة الصور. في هذه المقالة، سنشرح كيفية بناء قائمة مهام باستخدام coroutines في Kotlin، وسنتعرف أيضًا على مكتبة KJobQueue - وهو حل خفيف لإدارة المهام المتقدمة.
لماذا نحتاج إلى قائمة مهام؟
المشكلات الرئيسية التي تحلها قائمة المهام:
- ترتيب التنفيذ - يجب ألا تتعارض المهام على الموارد.
- الحد من التوازي - على سبيل المثال، لا يزيد عن 3 تحميلات متزامنة.
- معالجة الأخطاء وإعادة المحاولة - عند الفشل، يمكن إعادة تشغيل المهمة.
- الأولويات - يتم تنفيذ المهام العاجلة أولاً.
- مقاومة إعادة التشغيل - يمكن لقائمة المهام حفظ الحالة.
قائمة بسيطة باستخدام coroutines (Channel)
أبسط طريقة لتنفيذ قائمة هي استخدام Channel و coroutine معالج. مثال:
import kotlinx.coroutines.*import kotlinx.coroutines.channels.Channel
data class Task(val id: Int, val payload: String)
suspend fun processTask(task: Task) { println("معالجة المهمة ${task.id}: ${task.payload}") delay(500) // محاكاة العمل}
fun main() = runBlocking { val taskChannel = Channel<Task>(capacity = 10)
// تشغيل العامل val worker = launch { for (task in taskChannel) { processTask(task) } }
// إضافة المهام launch { repeat(5) { i -> taskChannel.send(Task(i, "بيانات $i")) } taskChannel.close() }
worker.join()}هذا الأسلوب مناسب للسيناريوهات البسيطة، لكنه لا يدعم الأولويات، إعادة المحاولة، أو حفظ الحالة.
KJobQueue - مكتبة لقائمة مهام متقدمة
KJobQueue (متاحة على GitHub) هي مكتبة خفيفة لـ Kotlin، مبنية فوق coroutines. توفر:
- قائمة ذات أولويات (بناءً على
Comparable). - الحد من التوازي (عدد المهام المنفذة في وقت واحد).
- إعادة محاولة تلقائية مع تأخير.
- دعم الإلغاء والإيقاف.
- مدير قابل للتخصيص (تجمع الخيوط).
التثبيت
أضف في build.gradle.kts:
dependencies { implementation("io.github.kjobqueue:kjobqueue-core:1.0.0")}مثال على استخدام KJobQueue
import io.github.kjobqueue.*import kotlinx.coroutines.*import kotlin.random.Random
class DownloadJob(val url: String, override val priority: Int = 0) : PriorityJob { override suspend fun execute() { println("تحميل $url (الأولوية $priority)") delay(1000) if (Random.nextBoolean()) throw RuntimeException("خطأ في الشبكة") }}
fun main() = runBlocking { val queue = JobQueue( maxConcurrent = 2, // بحد أقصى مهمتين في وقت واحد retryDelayMs = 500L, // تأخير قبل إعادة المحاولة maxRetries = 3 // بحد أقصى 3 محاولات )
queue.add(DownloadJob("https://example.com/file1", priority = 5)) queue.add(DownloadJob("https://example.com/file2", priority = 1)) queue.add(DownloadJob("https://example.com/file3", priority = 10))
delay(5000) // نعطي وقتًا للتنفيذ queue.shutdown()}معالجة الأخطاء وإعادة المحاولة
يقوم KJobQueue بمعالجة الاستثناءات تلقائيًا. إذا ألقت المهمة استثناءً، فإنها