إذا كنت تشاهد هذا على https://github.com/collectiveidea/delayed_job ، فأنت تقرأ الوثائق للفرع الرئيسي. عرض الوثائق لأحدث إصدار (4.1.13).
تأخر :: Job (أو DJ) يغلف النمط الشائع لتنفيذ المهام الطويلة بشكل غير متزامن في الخلفية.
إنه استخراج مباشر من Shopify حيث يكون جدول الوظائف مسؤولاً عن العديد من المهام الأساسية. من بين هذه المهام:
إرسال رسائل إخبارية ضخمة
تغيير حجم الصورة
HTTP التنزيلات
تحديث المجموعات الذكية
تحديث SOLR ، خادم البحث الخاص بنا ، بعد تغيير المنتج
واردات الدُفعات
شيكات البريد العشوائي
تابعنا على Twitter للحصول على تحديثات وإشعارات حول الإصدارات الجديدة.
تأخير _job 3.0.0 يدعم فقط Rails 3.0+.
يدعم Leveled_job العديد من الخلفية لتخزين قائمة انتظار الوظيفة. انظر الويكي للخلفية الأخرى.
إذا كنت تخطط لاستخدام تأخير _job مع سجل نشط ، فأضف delayed_job_active_record
إلى Gemfile
.
جوهرة "تأخير _job_active_record"
إذا كنت تخطط لاستخدام تأخير _job مع mongoid ، فأضف delayed_job_mongoid
إلى Gemfile
.
جوهرة "تأخير _job_mongoid"
قم بتثبيت bundle install
لتثبيت الواجهة الخلفية وتأخيرها.
يتطلب الواجهة الخلفية النشط جدول وظائف. يمكنك إنشاء هذا الجدول عن طريق تشغيل الأمر التالي:
rails generate delayed_job:active_record rake db:migrate
لصالح Rails 4.2+ ، انظر أدناه
في وضع التطوير ، إذا كنت تستخدم Rails 3.1+ ، فسيتم إعادة تحميل رمز التطبيق تلقائيًا كل 100 وظيفة أو عندما تنتهي قائمة الانتظار. لم تعد بحاجة إلى إعادة تشغيل الوظيفة المتأخرة في كل مرة تقوم فيها بتحديث الكود الخاص بك في التطوير.
في Rails 4.2+ ، قم بتعيين Queue_adapter في config/application.rb
config.active_job.queue_adapter =: تأخير _job
انظر دليل القضبان لمزيد من التفاصيل.
إذا كنت تستخدم جوهرة Protected_attributes ، فيجب أن تظهر قبل تأخير _job في Gemfile. إذا فشلت وظائفك في:
ActiveRecord::StatementInvalid: PG::NotNullViolation: ERROR: null value in column "handler" violates not-null constraint
ثم هذا هو الإصلاح الذي تبحث عنه.
تقدم الوظيفة المتأخرة 3.0.0 عمودًا جديدًا لجدول تأخير _jobs.
إذا كنت تقوم بالترقية من تأجيل الوظيفة 2.x ، فقم بتشغيل مولد الترقية لإنشاء ترحيل لإضافة العمود.
rails generate delayed_job:upgrade rake db:migrate
اتصل .delay.method(params)
على أي كائن وسيتم معالجته في الخلفية.
# بدون تأخير [email protected]! (@device)# مع تأخير [email protected]! (@Device)
إذا كان يجب تشغيل الطريقة دائمًا في الخلفية ، فيمكنك الاتصال بـ #handle_asynchronously
بعد إعلان الطريقة:
جهاز الفصل DEF تسليم طريقة المدى الطويل نهاية handle_asynchronous: deliverenddevice = device.newdevice.deliver
#handle_asynchronously
و #delay
تأخذ هذه المعلمات:
:priority
(الرقم): يتم تشغيل الأرقام الأدنى أولاً ؛ الافتراضي هو 0 ولكن يمكن إعادة تكوينه (انظر أدناه)
:run_at
(time): قم بتشغيل الوظيفة بعد هذا الوقت (ربما في المستقبل)
:queue
(السلسلة): قائمة الانتظار المسمى لوضع هذه المهمة في ، بديل للأولويات (انظر أدناه)
يمكن أن تكون هذه الكائنات procs ، مما يسمح بتقييم وقت الاتصال للقيمة.
على سبيل المثال:
فئة Longtasks def send_mailer# بعض الكود الآخر نهاية handle_asynchronous: send_mailer ،: الأولوية => 20 def in_the_future# بعض التعليمات البرمجية الأخرى نهاية # 5. minutes.from_now سيتم تقييمها عند استدعاء in_the_future handle_asynchronous: in_the_future ،: run_at => proc.new {5.minutes.from_now} def self.hen_to_run2.hours.from_now نهاية class << selfdef call_a_class_method # بعض codeendhandle_asynchronous: call_a_class_method ،: run_at => proc.new {when_to_run} نهاية attr_reader: How_imortant def call_an_instance_method# بعض التعليمات البرمجية الأخرى نهاية handle_asynchronously: call_an_instance_method ،: priority => proc.new {| i | i.how_imortant} نهاية
إذا كنت ترغب في استدعاء طريقة handle_asynchronously
دون تأخير الوظيفة ، على سبيل المثال أثناء تصحيح شيء ما في وحدة التحكم ، ما عليك سوى إضافة _without_delay
إلى اسم الطريقة. على سبيل المثال ، إذا كانت طريقتك الأصلية هي foo
، فاستدعاء foo_without_delay
.
يستخدم تأخر الوظيفة بناء جملة خاص للمراسلين. لا تستدعي طريقة .deliver
عند استخدام .delay
.
# بدون تأخير _jobnotifier.signup (user) .DeLiver# مع تأخير _jobnotifier.delay.signup (@user)# تأخير _job قيد التشغيل في timenotifier.delay محددة (run_at: 5.minutes.from_now) .signup (@user) ، يجب استدعاء طريقة. with قبل .delay methodNotifier.with (Foo: 1 ، Bar: 2) .Delay.Signup (@user)
قد ترغب أيضًا في التفكير في استخدام الوظيفة النشطة مع Mailer Action التي توفر بناء جملة .deliver_later
مريحة التي توجه إلى تأخير الوظيفة تحت الغطاء.
يقدم DJ 3 على طراز Resque المسماة مع الاستمرار في الاحتفاظ بأولوية على غرار DJ. الهدف من ذلك هو توفير نظام لتجميع مهام العمل من قبل تجمعات منفصلة من العمال ، والتي يمكن تحجيمها والتحكم فيها بشكل فردي.
يمكن تعيين الوظائف في قائمة انتظار عن طريق تعيين خيار queue
:
Object.Delay (: Queue => 'Tracking').
يمكنك تكوين الأولويات الافتراضية لقوائم الانتظار المسماة:
تأخر :: worker.queue_attributes = { High_priority: {الأولوية: -10} ، low_priority: {الأولوية: 10}}
يمكن تجاوز أولويات قائمة الانتظار التي تم تكوينها عن طريق نقل الأولوية إلى طريقة التأخير
Object.delay (: Queue => 'High_Priority' ، الأولوية: 0) .Method
يمكنك بدء العمليات للعمل فقط في طوابير معينة مع خيارات queue
queues
المحددة أدناه. بدأت العمليات دون تحديد قائمة انتظار ستدير وظائف من أي قائمة انتظار. للحصول على عملية تدير الوظائف بشكل فعال حيث لم يتم تحديد قائمة انتظار ، قم بتعيين اسم قائمة انتظار افتراضي باستخدام Delayed::Worker.default_queue_name
يمكن استخدام script/delayed_job
لإدارة عملية الخلفية التي ستبدأ في العمل في الوظائف.
للقيام بذلك ، أضف gem "daemons"
إلى Gemfile
وتأكد من قيامك بتشغيل rails generate delayed_job
.
يمكنك بعد ذلك القيام بما يلي:
RAILS_ENV=production script/delayed_job start RAILS_ENV=production script/delayed_job stop # Runs two workers in separate processes. RAILS_ENV=production script/delayed_job -n 2 start RAILS_ENV=production script/delayed_job stop # Set the --queue or --queues option to work from a particular queue. RAILS_ENV=production script/delayed_job --queue=tracking start RAILS_ENV=production script/delayed_job --queues=mailers,tasks start # Use the --pool option to specify a worker pool. You can use this option multiple times to start different numbers of workers for different queues. # The following command will start 1 worker for the tracking queue, # 2 workers for the mailers and tasks queues, and 2 workers for any jobs: RAILS_ENV=production script/delayed_job --pool=tracking --pool=mailers,tasks:2 --pool=*:2 start # Runs all available jobs and then exits RAILS_ENV=production script/delayed_job start --exit-on-complete # or to run in the foreground RAILS_ENV=production script/delayed_job run --exit-on-complete
Rails 4: استبدال البرنامج النصي/تأخير _job مع bin/eveled_job
يمكن أن يعمل العمال على أي جهاز كمبيوتر ، طالما أن لديهم إمكانية الوصول إلى قاعدة البيانات وساعتهم متزامنة. ضع في اعتبارك أن كل عامل سيتحقق من قاعدة البيانات كل 5 ثوان على الأقل.
يمكنك أيضًا استدعاء rake jobs:work
الذي سيبدأ العمل في الوظائف. يمكنك إلغاء مهمة RAKE مع CTRL-C
.
إذا كنت ترغب فقط في تشغيل جميع الوظائف المتاحة والخروج ، فيمكنك استخدام rake jobs:workoff
العمل خارج الطوابير عن طريق تعيين متغير QUEUE
أو QUEUES
.
QUEUE=tracking rake jobs:work QUEUES=mailers,tasks rake jobs:work
سيقوم بناء الجملة التالي بإعادة تشغيل الوظائف المتأخرة:
RAILS_ENV=production script/delayed_job restart
لإعادة تشغيل العديد من عمال التأخير:
RAILS_ENV=production script/delayed_job -n2 restart
Rails 4: استبدال البرنامج النصي/تأخير _job مع bin/eveled_job
الوظائف هي كائنات روبي بسيطة مع طريقة تسمى أداء. يمكن أن يكون أي كائن يستجيب للأداء محشوة في جدول الوظائف. يتم تسلسل الأشياء الوظيفية إلى Yaml بحيث يمكن إحياءها لاحقًا من قبل عداء الوظائف.
النشرة الإخبارية = struct.new (: نص ،: رسائل البريد الإلكتروني) تفعل def performails.ach {| e | NewsletTermailer.deliver_text_to_email (نص ، ه)} Endenddelayed :: Job.Enqueue NewsletterJob.new ('lorem ipsum ...' ، customer.pluck (: email))
لتعيين محاولات MAX لكل JOB التي تتجاوز التأخير :: العامل
النشرة الإخبارية = struct.new (: نص ،: رسائل البريد الإلكتروني) تفعل def performails.ach {| e | NewsletTermailer.deliver_text_to_email (نص ، ه)} نهاية def max_attempts3 انقض
لتعيين وقت تشغيل لكل Job Max يتجاوز التأخير:
ملاحظة: لا يمكن استخدام هذا إلا لضبط max_run_time أقل من تأخير :: worker.max_run_time. وإلا فإن القفل على الوظيفة سوف ينتهي وسيبدأ عامل آخر العمل على وظيفة قيد التقدم.
النشرة الإخبارية = struct.new (: نص ،: رسائل البريد الإلكتروني) تفعل def performails.ach {| e | NewsletTermailer.deliver_text_to_email (نص ، ه)} نهاية def max_run_time120 # seconds انقض
لتعيين افتراضي لكل JOB لتدمير الوظائف الفاشلة التي تتجاوز التأخير: طريقة في الوظيفة
النشرة الإخبارية = struct.new (: نص ،: رسائل البريد الإلكتروني) تفعل def performails.ach {| e | NewsletTermailer.deliver_text_to_email (نص ، ه)} نهاية DEF DRIDER_FAILED_JOBS؟ خطأ انقض
لتعيين اسم قائمة انتظار افتراضي لوظيفة مخصصة تتأخر:
النشرة الإخبارية = struct.new (: نص ،: رسائل البريد الإلكتروني) تفعل def performails.ach {| e | NewsletTermailer.deliver_text_to_email (نص ، ه)} نهاية def queue_name'newsletter_queue ' انقض
عند الخطأ ، يتم جدولة المهمة مرة أخرى في 5 ثوان + N ** 4 ، حيث N هو عدد المحاولات. يمكنك تحديد طريقة reschedule_at
الخاصة بك لتجاوز هذا السلوك الافتراضي.
النشرة الإخبارية = struct.new (: نص ،: رسائل البريد الإلكتروني) تفعل def performails.ach {| e | newsletTermailer.deliver_text_to_email (نص ، ه)} نهاية def regchedule_at (current_time ، محاولات) Current_time + 5.Seconds انقض
يمكنك تحديد السنانير على وظيفتك التي سيتم استدعاؤها في مراحل مختلفة في هذه العملية:
ملاحظة: إذا كنت تستخدم ActiveJob ، فهذه السنانير غير متوفرة لوظائفك. ستحتاج إلى استخدام عمليات الاسترجاعات الخاصة بـ ActiveJob. يمكنك العثور على تفاصيل هنا https://guides.rubyonrails.org/active_job_basics.html#callbacks
فئة paranoidnewsletterjob <newsletterjob def enqueue (Job) record_stat 'Newsletter_job/enqueue' نهاية def performails.ach {| e | NewsletTermailer.deliver_text_to_email (نص ، ه)} نهاية def قبل (Job) record_stat 'Newsletter_job/start' نهاية def بعد (Job) record_stat 'Newsletter_job/eart' نهاية Def Success (Job) record_stat 'Newsletter_job/success نهاية DEF Error (Job ، استثناء) Airbrake.Notify (استثناء) نهاية Def Failure (Job) page_sysadmin_in_the_middle_of_the_night انقض
تدور المكتبة حول جدول تأخير _jobs الذي يبدو على النحو التالي:
create_table: تأخير _jobs ،: force => true do | table | Table.Integer: الأولوية ،: الافتراضي => 0 # يسمح لبعض الوظائف بالقفز إلى مقدمة قائمة الانتظار Table.Integer: المحاولات ،: الافتراضي => 0 # يوفر إعادة المحاكاة ، ولكن لا يزال يفشل في النهاية. Table.Text: سلسلة معالج # yaml المشفرة للكائن الذي سيعمل Table.Text: Last_error # سبب الفشل الأخير (انظر الملاحظة أدناه) Table.DateTime: Run_at # متى يتم تشغيله. يمكن أن يكون الوقت. ZONE.NOW على الفور ، أو في وقت ما في المستقبل. Table.DateTime: Locked_at # تعيين عندما يعمل العميل على هذا الكائن table.dateTime: فشل exit_at # عندما فشلت جميع عمليات إعادة المحاكاة (في الواقع ، افتراضيًا ، يتم حذف السجل بدلاً من ذلك) Table.String: locked_by # من يعمل على هذا الكائن (إذا كان مغلقًا) Table.String: قائمة الانتظار # اسم قائمة الانتظار هذه المهمة في table.timestampsend
عند الخطأ ، يتم جدولة المهمة مرة أخرى في 5 ثوانٍ + N ** 4 ، حيث N هو عدد المحاولات أو باستخدام طريقة reschedule_at
المحددة للوظيفة.
Worker.max_attempts
هو 25. بعد ذلك ، يتم حذف المهمة (الافتراضي) ، أو تركها في قاعدة البيانات مع مجموعة "FAIL_AT". مع الافتراضي 25 محاولة ، ستكون آخر إعادة محاولة بعد 20 يومًا ، مع الفاصل الزمني الأخير ما يقرب من 100 ساعة.
Worker.max_run_time
الافتراضي. max_run_time هو 4. ساعات. إذا استغرقت وظيفتك وقتًا أطول من ذلك ، يمكن أن يستقله كمبيوتر آخر. الأمر متروك لك للتأكد من أن وظيفتك لا تتجاوز هذه المرة. يجب عليك ضبط هذا على أطول وقت تعتقد أن المهمة قد تتخذها.
بشكل افتراضي ، ستحذف الوظائف الفاشلة (ويحذف دائمًا وظائف ناجحة). إذا كنت ترغب في الاحتفاظ بالوظائف الفاشلة ، فقم بتعيين Delayed::Worker.destroy_failed_jobs = false
. سيتم وضع علامة على الوظائف الفاشلة مع فشل غير null.
بشكل افتراضي ، يتم جدولة جميع الوظائف priority = 0
، وهي أولوية قصوى. يمكنك تغيير هذا عن طريق إعداد Delayed::Worker.default_priority
إلى شيء آخر. الأرقام المنخفضة لها أولوية أعلى.
السلوك الافتراضي هو قراءة 5 وظائف من قائمة الانتظار عند العثور على وظيفة متاحة. يمكنك تكوين هذا عن طريق إعداد Delayed::Worker.read_ahead
.
بشكل افتراضي ، سيتم قائمة الانتظار في قائمة الانتظار بدون قائمة انتظار مسماة. يمكن تحديد قائمة انتظار الافتراضية المسماة باستخدام Delayed::Worker.default_queue_name
.
إذا لم يتم العثور على وظائف ، ينام العامل لمقدار الوقت المحدد بواسطة خيار تأخير النوم. تعيين Delayed::Worker.sleep_delay = 60
لوقت نوم 60 ثانية.
من الممكن تعطيل الوظائف المتأخرة لأغراض الاختبار. تعيين Delayed::Worker.delay_jobs = false
لتنفيذ جميع الوظائف في الوقت الفعلي.
أو Delayed::Worker.delay_jobs
تأخير :: worker.delay_jobs = -> (Job) { job.queue! = 'inline'}
SignalException
تحتاج إلى إثارة استثناءات على إشارات sigterm ، Delayed::Worker.raise_signal_exceptions = :term
الافتراضي لهذا الخيار خطأ.
فيما يلي مثال على تغيير معلمات الوظيفة في القضبان:
# config/initializers/evention_job_config.rbdelayed :: worker.destroy_failed_jobs = falsedelayed :: worker.sleep_delay = 60delayed :: worker.max_attempts = 3delayed :: worker.max_runt default_queue_name = 'default'delayed :: worker.delay_jobs =! rails.env.test؟ تأخير: تأخير _job.log ')
يمكنك استدعاء rake jobs:clear
لحذف جميع الوظائف في قائمة الانتظار.
أماكن جيدة للحصول على المساعدة هي:
مجموعات Google حيث يمكنك الانضمام إلى قائمتنا البريدية.
stackoverflow