Fabric: تم فصل المحطة المحلية stdin إذا تضمن تشغيل ThreadingGroup وضع السكون

تم إنشاؤها على ٢٥ يونيو ٢٠١٨  ·  22تعليقات  ·  مصدر: fabric/fabric

أنا أستخدم مجموعة مؤشرات الترابط لتشغيل أوامر shell. بعد تشغيل البرنامج النصي الذي يتضمن sleep ، يتم ترك المحطة المحلية مع stdin منفصلة (ضغطات المفاتيح غير مرئية في سطر الأوامر) ويجب إعادة تعيين المحطة الطرفية.

لقد جربت هذا عدة مرات ووجدت أنه يحدث فقط مع ThreadingGroups (SerialGroups على ما يرام). يمكن أن يكون أمر السكون في أي مكان في سطر واحد (الأمر الأول ، الأوسط ، الأخير) ويمكن ضمه في سطر واحد إما بفاصلة منقوطة ، أو علامة عطف مزدوجة. تعمل جميع الأوامر كما هو متوقع ، ولكن تظل المحطة الطرفية في حالة سيئة.

الغريب ، إذا خرج التشغيل السابق مع استثناء غير معلوم ، فلن تتأثر المحطة.

لإعادة إنتاج:

from fabric import ThreadingGroup as Group

# raise ValueError()
remotes = Group("host1.example.com", "host2.example.com")
result = remotes.run("echo 1; sleep 1; echo 2")

قم بتشغيل البرنامج النصي أعلاه. بعد أن يخرج ، اكتب شيئًا في سطر الأوامر. إذا لم تجد أي ناتج ، <ctrl>+c واكتب reset<enter> . لمشاهدة سلوك ما بعد الاستثناء ، قم بإلغاء التعليق على السطر raise ، وقم بتشغيل الكود ، وعلق على السطر ، ثم قم بتشغيله مرتين أخريين. أول تشغيل ناجح سيترك المحطة في حالة جيدة. الثانية ستترك stdin منفصلة.

اكتشفت هذه المشكلة مع sleep في اختباري ، لكن من المحتمل أن يكون للأوامر الأخرى نفس التأثير. هناك أيضًا فرصة لأني أفعل شيئًا خاطئًا. إذا كان هذا هو الحال ، اعتذاري.

الإعداد الخاص بي:
بيثون 3.6.4
قماش 2.1.3
OSX 10.13.5 ، الاتصال بـ Ubuntu 14.04

Bug Needs investigation

ال 22 كومينتر

انظر # 1814 كحالة مشكلة قابلة لإعادة الإنتاج ثانية.

يبدو هذا وكأنه خطأ شرعي بالنسبة لي ولست متأكدًا من سبب ذلك. يمكن أن تكون الروائح مثل مشكلة يونكس عامة مع ربط الأنابيب الطرفية بعمليات فرعية متعددة في وقت واحد ، أو (على سبيل المثال رقم 1814) حالة سباق حول حالة الأنابيب ، أو شيء من هذا القبيل.

سنحاول التكاثر والتشويش على سبب / حل.

أيضًا ، ربما يتطلب هذا إصلاحًا على مستوى الاستدعاء وقد يكون محضًا في مجاله (بقدر ما لم أفعل الكثير مع الترابط في سياق استدعاء خالص حتى الآن ؛ ولكن انظر على سبيل المثال pyinvoke / استدعاء # 194 - إنه شيء يجب أن يحدث هناك أيضًا). في هذه الحالة سوف أنقل هذا إلى تذكرة هناك وسيكون "إصلاح" النسيج هو ترقية Invoke بمجرد إصدار الإصلاح.

كنت على Ubuntu 16.04.2 متصلاً بنفس الشيء.

تقرير آخر عن نفس القضية في # 1829. هذا في معلمي التالي لإصلاح الأخطاء وسأركز على ذلك اليوم التالي الذي نأمل أن يكون OSS (الاثنين).

لقد حاولت للتو إعادة إنتاج هذا (2.0 فرع ، Python 3.6.4 ، macOS 10.12) ولم أتمكن من ذلك ، للأسف. جربت أولاً مضيفًا محليًا مزدوجًا ، ثم مثيلين منفصلين للسحابة البعيدة ، بدون أحجار نرد في كلتا الحالتين ؛ طريقي بخير بعد ذلك.

سأحاول استخدام حاوية Linux قليلاً في حالة ما إذا كان ذلك مفيدًا ، ولكن نظرًا لأن OP كان أيضًا على macOS ، فلست متأكدًا من أنه سيحدث فرقًا. سأحاول أيضًا تشغيله في حلقة لمعرفة ما إذا كان مجرد إعداد عرضي.

سأجربه أيضًا على 2.1 في حال قدمناه بطريقة ما في 2.1 ، يبدو أن هذا غير مرجح للغاية.

jensenak @ nicktimko هل أنت

bitprophet على 2.1.3 كان يحدث في سير العمل الفعلي غالبًا إلى حد ما (> 80٪ ، كنت أذهب أيضًا بالتوازي مع 6 خوادم ، وليس 2) ، على الرغم من أنه في المثال المبتكر الخاص بي من # 1814 هو أقل بكثير ، ربما 20 ٪. يمكنني محاولة التوصل إلى إعداد Docker ، أو فشل إعداد Vagrant في إعداده.

bitprophet لقد كان هذا 100٪ من الوقت بالنسبة لي. فقط للتأكد ، بدأت في Virtualenv جديد مع تثبيت النسيج فقط. لقد اختبرت 2.0 و 2.1 و 2.2. أنتج رمز المثال الذي قمت بلصقه السلوك الموصوف في كل مرة. في جميع الاختبارات ، كنت أقوم بالاتصال بوحدات التحكم عن بعد Ubuntu 14.04.

أنا أستخدم إصدارًا مختلفًا من OSX (10.13). ربما هذا مرتبط؟ على الرغم من أن nicktimko لم يكن موجودًا على OSX على الإطلاق.

في حالة وجود إصدار آخر يمثل مشكلة ، فإليك الشكل الذي بدا عليه pip freeze في Virtualenv الخاص بي:

asn1crypto==0.24.0
bcrypt==3.1.4
cffi==1.11.5
cryptography==2.3
fabric==2.2.1
idna==2.7
invoke==1.1.0
paramiko==2.4.1
pyasn1==0.4.4
pycparser==2.18
PyNaCl==1.2.1
six==1.11.0

نظرًا لأن كل هذه العناصر قد تم تثبيتها على أنها تبعيات للنسيج 2.2 ، أتوقع أن تبدو إصداراتك متشابهة.

إذا كان هناك المزيد الذي يمكنني فعله للمساعدة ، فأنا أكثر من راغب في ذلك. فقط لست متأكدا حقا أين آخر للبحث.

ما الالتزام الذي يجب أن أختبره ؛ هل أجريت أي تغييرات مؤخرًا قد تؤثر على الأشياء؟ سأحاول مع التجميد أعلاه ، يمكنك أيضًا تقديم reqs.txt آخر مجمدة ويمكنني معرفة ما إذا كان ذلك يعمل أم لا.

nicktimkojensenak شكرا للمعلومات اضافية. سأستمر في محاولة إعادة عرضه هنا ؛ بنسبة 20٪ ، لم أكن بالتأكيد أحاول القيام بذلك بشكل كافٍ. كانت أجهزة التحكم عن بُعد الخاصة بي من نوع Mac وبعض Debians الأقدم ، يمكنني تجربة Ubuntu Trusty في حال كانت خاصة بذلك (وهو أمر غريب ، لكن هذا الأمر برمته غريب.)

أيضًا ، ما هي بيئات الصدفة المحلية الخاصة بك؟ Mine هو zsh على (مرة أخرى ، macOS 10.12) المدمج في Terminal.app ، داخل tmux. سأحاول أيضًا بعض التباديل حول تلك الزاوية قليلاً.

AHA. يبدو أن هذا خاص باش! ما زلت غير قادر على التراجع تحت zsh خارج tmux ، لكن في اللحظة التي أحاول فيها تحت bash ، أحصل على الأعراض المذكورة على الفور. نفس الشيء داخل tmux ، لذلك ليس لـ tmux أي تأثير - إنه شيء صدفة.

_لماذا_ سيتصرف هذا بشكل مختلف تحت bash vs zsh ، ليس لدي فكرة فورية. يمكن أن تكون محددة لكيفية تنفيذها ، أو (يبدو أكثر احتمالية) ربما شيء ما في ملفات zsh dotfiles الخاص بي يمنع المشكلة؟ سيتعين عليك البحث ... على الرغم من أن تحديد حل على جانب Python ضروري في كلتا الحالتين على الأرجح.

تحرير: أيضًا ، يحدث الاستنساخ حتى عند الاتصال بـ sshd الخاص بالمضيف المحلي الخاص بي عدة مرات في نفس الوقت ، وهذا ليس مفاجئًا للغاية. لذلك يبدو أن الطرف البعيد لا يهم.

أيضًا ، حاولت التحقق من الملاحظة حول "التشغيل السابق باستثناء منع المشكلة للتشغيل التالي فقط" ولكن هذا لم يحدث بالنسبة لي ؛ أحصل على السلوك في كل مرة بغض النظر.

Moar: أزلت sleep لمعرفة ما سيحدث ؛ ما زلت قادرًا على التكاثر ، على الرغم من أنها الآن متقطعة بعض الشيء (على الرغم من أن هذا ليس من السهل إعادة إنتاجه في حلقة تلقائية ، كل ذلك يتم عن طريق التكاثر اليدوي ، مما يعني انخفاض عدد حالات الاختبار ، مما يعني أن النسبة المئوية الحقيقية للظهور ستكون حقيقية يصعب قياسه بدقة.)

هذا جيد أيضًا ، كلما قل عدد المشغلات الغريبة ، كان ذلك أفضل. هذه الرائحة تشبهها _يجب_ أن يكون خطأ خيطًا أساسيًا غبيًا في مكان ما ، والذي لن يتأثر عادةً بأي شيء محدد على الطرف البعيد أو المحلي بصرف النظر عن طول الوقت الذي يجعل حالة السباق (أو w / e) أكثر احتمالية.

أتساءل عما إذا كان هذا مرتبطًا بـ pyinvoke / استدعاء # 552 والذي يتلخص في معالجة الاستثناء الخاص بـ Invoke الفئة الفرعية للخيط (المستخدمة في ThreadingGroup هنا) من المحتمل أن يكون قد تسبب في فشل اكتشاف موت الخيط.

سيتعين علينا التأكد من أنني أفهم أن (إصلاحه المحتمل ، pyinvoke / استدعاء # 553 ، لم يكن دمجًا مؤقتًا لأنه بدا غريبًا أننا حصلنا على شيء وظيفي ظاهر ، وخاطئ جدًا) ثم انظر ما إذا كان تطبيقه يجعل تختفي هذه الأعراض.

أزلت النوم لأرى ما سيحدث ؛ ما زلت قادرًا على التكاثر ، على الرغم من أنه أصبح الآن أكثر تقطعًا بعض الشيء

تبدو مثل حالة الاختبار التي أمتلكها ، حيث كنت بحاجة إلى ضربها عدة مرات قبل أن تنفجر. يبدو أن لديك التعامل الجيد معها

لاحظت اليوم أنني لا أستطيع أيضًا إعادة إنتاج سلوك الاستثناء الذي وصفته منذ شهر ... لسوء الحظ ، لا أتذكر ما كنت أفعله في ذلك الوقت. : /

أنا بالفعل أدير باش هنا. بحث جيد. حقيقة أن المشكلة متقطعة بدون النوم تجعلني أتساءل عما إذا كانت هذه حالة عرقية من نوع ما.

أنت تقول ذلك ، لكن الآن لا يمكنني إعادة صياغته مرة أخرى ، أو على الأقل متقطع جدًا. إعادة النوم تجعله يأتي كثيرًا. فلدي حب السباق الظروف.

بالنظر إلى قضية الاستدعاء هذه ، يذكر المراسل محطة فاشلة كعرض ؛ لكن الغريب أنني لا أستطيع إعادة إنتاج أعراض هذه حتى تحت باش ، مع الكود الخاص به. ما زلت لن أتفاجأ إذا كان السبب الجذري هو نفسه (يتعلق ببعض الأشياء حول موت الخيط وإغلاق stdin ، أو ربما العودة إلى التخزين المؤقت الخطي ، بشكل صحيح قبل الخروج).

التحقق من نقاط المشكلة الأخرى المذكورة ، مقابل قضية repro هنا:

  • لا يبدو أن ExceptionHandlingThread.is_dead بت مهم ، فمن المفترض أن يكون صحيحًا ، وهو أمر منطقي لأنه يهدف إلى التعامل مع الاستثناءات في سلسلة الرسائل ولا تتعامل أي من هذه الحالات مع الاستثناءات. is_dead هو False لجميع سلاسل العمليات الثلاثة (stdin / out / err) عندما أتوقع أن تكون كذلك.
  • التأكيد على أننا لا نغلق العملية الفرعية بشكل صحيح يبدو أقرب إلى العلامة ؛ إذا كان ذلك يترك stdin الطرفية المسيطرة مرتبطًا بموصف ملف ميت الآن أو شيء من هذا القبيل ...؟ (يجب أن أعرف بشكل أفضل ما يحدث في هذه الحالة على أي حال).

    • باستثناء ... في حالة Fabric ، لا توجد عملية فرعية محلية ولا يوجد عبور مباشر لواصفات الملفات ، لذلك لا يمكن أن يكون هذا هو الحال.

    • بمعنى أنه من المرجح أن تكون القضية شيئًا آخر؟


محاولة مسار آخر ... ماذا عن بيئة المحطة الطرفية بالضبط بعد ظهور الخطأ ، هل تغيرت؟ عند تشغيل stty -a ظل bash مع وجود تلف خطأ أو بدونه ، فإن الاختلافات التي يمكنني رؤيتها هي:

  • lflags : المحطة الطرفية التي تم التنصت عليها -icanon ، -echo ، -pendin (مقابل المصطلح العادي حيث تفتقر جميعها إلى علامة الطرح). يبدو عدم ترديد الصدى مشكلة بالتأكيد ، بافتراض أن هذا ما يعنيه ذلك.
  • iflags : bugged-out لديه -ixany و ignpar (المثال الأول لشيء يتم تعيينه ، وليس غير محدد ، في الإعداد السيئ)
  • oflags و cflags متطابقان ، مثل cchars (سأكون غريبًا جدًا إذا تغيرت أحرف التحكم ...)

وفقًا لـ man stty :

  • icanon يتحكم في معالجة ERASE و KILL ؛ ربما ليس فرقًا كبيرًا (قد يكون سبب ضبط هذا أو عدم ضبطه أمرًا مثيرًا للاهتمام)
  • echo هو ما يبدو عليه الأمر ، سواء أكان مرددًا أم لا ، ومن الواضح أنه أكبر مشكلة عملية في الخطأ.
  • pendin ما إذا كان الإدخال (بافتراض stdin) معلقًا بعد التبديل الكنسي (وبما أن icanon انقلب بوضوح ... نعم) وستتم إعادة الإدخال عندما تصبح القراءة معلقة أو المزيد من المدخلات يصل. ليس من الواضح سبب أهمية هذا ، أو سبب ضبطه بشكل طبيعي وعدم ضبطه عند التنصت (كنت أتوقع الأخير ، إن وجد).
  • يسمح ixany لأي حرف بـ "بدء الإخراج" (وعندما لا يتم تعيينه ، يسمح فقط بـ START. حسنًا؟)
  • يعني ignpar تجاهل (أو إلغاء التعيين ، لعدم تجاهل) الأحرف التي بها أخطاء تماثل.

بشكل عام ، يبدو أنه يتم تطبيق "وضع" من المستوى الأعلى على الجهاز ، على غرار الطريقة التي قمنا بها بتعيين stdin للقراءة المخزنة بالأحرف للسماح لنا بقراءة 1 بايت في كل مرة بدلاً من الانتظار حتى تدخل رسائل المستخدم.

الذي يبدو مثل السلوك تحت العرض (نوعًا من ...) ، والذي كنت أتساءل عنه سابقًا ؛ لكن قراءة الكود المعني (لأن ملف التصحيح هذا يذكره أيضًا ، على الرغم من إعادة: موت الخيط) ، فإن تغيير الوضع تتم صياغته كمدير سياق ، لذلك _يجب _ دائمًا عدم ضبطه بغض النظر عن كيفية خروجنا من تلك الحلقة. لكنني سأحتاج إلى التحقق من ذلك ثلاث مرات الآن.

ثانوي: مجرد قول stty echo لتعيين echo كافٍ "لإصلاح" المحطة ؛ حتى لو لم يتم ضبط icanon و pendin وما إلى ذلك. لا يساعد حقًا ولكن مهلا ، من الجيد أن أعرف على ما أعتقد.

نعم! أعتقد أنني اكتشفت ذلك ، أثناء التحديق في مدير السياق هذا: ربما يرجع السبب في ذلك إلى أن مدير السياق يلتقط الحالة الطرفية الحالية لاستعادتها عند إغلاق الكتلة. لكن ماذا سنفعل في هذه الحالة؟ نحن نقوم بتشغيل اثنين من سلاسل المحادثات المنفصلة عالية المستوى ، كل منهما يشغل _نسخته الخاصة _ من مدير السياق هذا!

وفي Invoke ، بينما نعتزم أن نكون آمنين بخيوط المعالجة ، فإننا لا نختبر حاليًا أي شيء سوى سلاسل الإدخال / الإخراج ذات المستوى المنخفض الخاصة بنا ؛ 99٪ من "سلامة الخيط" هي ببساطة استخدام حالة كائن مكتفية ذاتيًا بدلاً من حالة الوحدة النمطية العالمية لـ Fabric 1. لذا فإن هذا الجزء الخاص من حفظ الدولة لا يتم تشغيله بشكل متزامن مع نفسه (جزئيًا لأن "الدولة" هي حرفياً المحطة المسيطرة ، والتي لا يوجد منها سوى واحدة ، لذا ... دولة عالمية ...).

لم أقم بإثبات ذلك بنسبة 100 ٪ حتى الآن (على وشك) ولكن لا توجد طريقة لم يكن الأمر كذلك. مؤشر الترابط الذي يتم تشغيله الثاني من المحتمل بشكل كبير التقاط سمات المحطة الطرفية للتحكم _after_ قام مؤشر الترابط الأول بالفعل بتعيينه في وضع المخزن المؤقت للحروف ؛ ثم ، إذا كان هذا الخيط الثاني أيضًا _ إنهاء _ ثانيًا (مرة أخرى ، على الأرجح ولكن غير مؤكد) فإنه "يستعيد" الحالة السيئة ، مما يؤدي بشكل فعال إلى التراجع عن استعادة مؤشر الترابط الأول.

تم التأكيد على أن علم ECHO ، على سبيل المثال ، يتم التقاطه بالتأكيد بواسطة مدير السياق غير الأول ، ثم يتم استعادته بنفسه. العمل على حل ، والذي أعتقد أنه سينتهي به الأمر فقط إلى "محاولة اكتشاف ما إذا كانت setcbreak تبدو مطبقة بالفعل ، وعدم التشغيل في هذه الحالة بدلاً من القيام برقصة اللقطة والتعديل والاستعادة".

يجب أن يكون له تأثير مقصود ، يكون أكثر نظافة بشكل هامشي للإقلاع (لا يتم تشغيل setcbreak> مرة واحدة أبدًا) ويتجنب حالة الركن حيث قد يؤدي الإصلاح الساذج دائمًا إلى تعيين ECHO ، وما إلى ذلك على "تشغيل" - والذي قد يتوقف في المواقف التي يكون فيها البث المعني tty-like ولكن تم ضبطه على عدم الترديد. (من غير المحتمل ، بالتأكيد ، لكن ليس مستحيلًا على الأرجح).

نظرًا لأن هذه مشكلة تتعلق بالاستدعاء فقط ، فسأعطيها مكانًا على هذا المتتبع - أتوقع إجراء اختبار وإصلاح لهذا قريبًا ، ولكن إذا كان لديك أي شيء آخر لإضافته ، فالرجاء الانتقال إلى https : //github.com/pyinvoke/invoke/issues/559

لكي تكون واضحًا تمامًا ، بمجرد أن يتم إصلاح ذلك ، يجب أن يتم إصداره في Invoke 1.0.2 / 1.1.1 (وربما 1.2.0 إذا حصلت على ذلك في نفس الوقت) و _ لا_ يجب أن تكون ترقيات النسيج ضرورية ، فقط Invoke.

تضمين التغريدة يعمل بعد ترقية Invoke :)
شكرا على مجهودك.

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات