لماذا تؤخر العمليات من قبل كرون ينتهي الأمر بفرد؟
-
19-09-2019 - |
سؤال
لدي بعض العمليات تظهر كما <defunct>
في top
(و ps
). لقد تغلبت الأشياء من البرامج النصية الحقيقية والبرامج.
في crontab
:
* * * * * /tmp/launcher.sh /tmp/tester.sh
محتويات launcher.sh
(وهو بالطبع ملحوظا قابل للتنفيذ):
#!/bin/bash
# the real script does a little argument processing here
"$@"
محتويات tester.sh
(وهو بالطبع ملحوظا قابل للتنفيذ):
#!/bin/bash
sleep 27 & # the real script launches a compiled C program in the background
ps
يظهر ما يلي:
user 24257 24256 0 18:32 ? 00:00:00 [launcher.sh] <defunct>
user 24259 1 0 18:32 ? 00:00:00 sleep 27
لاحظ أن tester.sh
لا يظهر - لقد خرجت بعد إطلاق وظيفة الخلفية.
لماذا launcher.sh
عصا حولها، ملحوظ <defunct>
ب يبدو فقط أن تفعل هذا عند إطلاقه cron
- لا عند تشغيله بنفسي.
مذكرة إضافية: launcher.sh
هو برنامج نصي مشترك في النظام يتم تشغيله، وهو ما لا يتم تعديله بسهولة. الأشياء الأخرى (crontab
, tester.sh
, ، حتى البرنامج الذي أجري بدلا من sleep
) يمكن تعديلها بسهولة أكبر.
المحلول
لأنهم لم يكونوا موضوع wait(2)
مكالمة النظام.
نظرا لأن شخصا ما قد ينتظر هذه العمليات في المستقبل، فإن النواة لا يمكن أن تتخلص منهم تماما أو لن يكون قادرا على تنفيذ wait
نداء النظام لأنه لن يكون لديه حالة الخروج أو دليل على وجودها بعد الآن.
عندما تبدأ واحدة من Shell، فإن Shell الخاص بك هي محاصرة Sigchld وعمليات الانتظار المختلفة على أي حال، لذلك لا شيء يبقى باقلا لفترة طويلة.
لكن كرون ليس في حالة الانتظار، فهو نائم، لذلك قد يلتصق الطفل المنفصل لفترة من الوقت حتى يستيقظ كرون.
تحديث: الاستجابة للتعليق ... هم. لقد تمكنت من تكرار المشكلة:
PPID PID PGID SESS COMMAND
1 3562 3562 3562 cron
3562 1629 3562 3562 \_ cron
1629 1636 1636 1636 \_ sh <defunct>
1 1639 1636 1636 sleep
لذلك، ماذا حدث، أعتقد:
- يبدأ Cron Forks و Chron Child Shell
- شل (1636) يبدأ SID و PGID 1636 ويبدأ النوم
- مخارج شل، Sigchld أرسلت إلى Cron 3562
- يتم تجاهل الإشارة أو مشاركتها
- قذيفة تحول غيبوبة. لاحظ أن النوم يعود لإحداثها، لذلك عندما يخرج النوم الإناث سيحصل على الإشارة والتنظيف. ما زلت أحاول معرفة متى يتم غياد الزومبي. ربما مع عدم وجود أطفال نشط Cron 1629 أرقام يمكن الخروج، عند تلك النقطة، سيتم إعادة إيلاء غيبوبة للتغليف والحديث. حتى الآن نحن نتساءل عن Sigchld المفقود الذي يجب أن تتم معالجة كرون.
- انها ليست بالضرورة خطأ vixie كرون. كما ترون هنا، Libdaemon يثبت معالج SIGCHLD خلال
daemon_fork()
, ، وهذا يمكن أن يتداخل مع تسليم الإشارات على الخروج السريع من قبل الوسيط 1629الآن، لا أعرف حتى إذا تم بناء Vixie Cron على نظام Ubuntu الخاص بي مع LIBDaemon، ولكن على الأقل لدي نظرية جديدة. :-)
- انها ليست بالضرورة خطأ vixie كرون. كما ترون هنا، Libdaemon يثبت معالج SIGCHLD خلال
نصائح أخرى
أظن أن كرون ينتظر جميع الإجراءات الفرعية في الجلسة لإنهاء. انظر الانتظار (2) فيما يتعلق بحجج PID السلبية. يمكنك أن ترى Sess مع:
ps faxo stat,euid,ruid,tty,tpgid,sess,pgrp,ppid,pid,pcpu,comm
إليك ما أراه (تم تحريره):
STAT EUID RUID TT TPGID SESS PGRP PPID PID %CPU COMMAND
Ss 0 0 ? -1 3197 3197 1 3197 0.0 cron
S 0 0 ? -1 3197 3197 3197 18825 0.0 \_ cron
Zs 1000 1000 ? -1 18832 18832 18825 18832 0.0 \_ sh <defunct>
S 1000 1000 ? -1 18832 18832 1 18836 0.0 sleep
لاحظ أن SH والنوم في نفس سيس.
استخدم الأمر SetSID (1). إليك Tester.Sh:
#!/bin/bash
setsid sleep 27 # the real script launches a compiled C program in the background
لاحظ أنك لا تحتاج &
, ، ساعد يضعه في الخلفية.
رأيي ناجم عن روند العمليات (ناجمة من قبل كروند لكل مهمة) في انتظار المدخلات على Stdin التي يتم ربطها إلى Stdout / Stderr من الأمر في Crontab. يتم ذلك لأن Cron قادر على إرسال الإخراج الناتج عبر البريد إلى المستخدم.
حتى لا ينتظر Crond ل EOF حتى أمر المستخدم وجميع عمليات الأطفال المستأجرة قد أغلقت الأنبوب. إذا تم ذلك، يستمر Crond مع بيان الانتظار ثم يختفي أمر المستخدم المنفصل.
لذلك أعتقد أنك يجب أن تفصل بشكل صريح عن كل الإعانات الفرعية المزروعة في البرنامج النصي الخاص بك في شكل الأنبوب (على سبيل المثال عن طريق إعادة توجيهه إلى ملف أو / dev / null.
لذلك يجب أن يعمل الخط التالي في Crontab:
* * * * * ( /tmp/launcher.sh /tmp/tester.sh &>/dev/null & )
أود أن أوصي بأن تحل المشكلة ببساطة عن طريق عدم وجود عمليتين منفصلين: launcher.sh
القيام بذلك على السطر الأخير:
exec "$@"
سيؤدي هذا إلى القضاء على العملية الزائدة.
لقد وجدت هذه السؤال أثناء البحث عن حل مع مشكلة مماثلة. لسوء الحظ، لم تحل الإجابات في هذا السؤال مشكلتي.
إن قتل العملية المنفذة ليست خيارا ما تحتاجه للعثور على العملية الأصلية وقتلتها. انتهى بي الأمر بقتل العمليات المنفذة بالطريقة التالية:
ps -ef | grep '<defunct>' | grep -v grep | awk '{print "kill -9 ",$3}' | sh
في "GREP" "يمكنك تضييق نطاق البحث في عملية منفصلة محددة، بعد.
لقد اختبرت نفس المشكلة عدة مرات. وأخيرا لدي الحل. فقط حدد "/ bin / bash" قبل البرنامج النصي باش كما هو موضح أدناه.
* * * * * / bin / bash / tmp/launcher.sh /tmp/tester.sh