Fabric: Terminal lokal stdin terlepas jika menjalankan ThreadingGroup termasuk tidur

Dibuat pada 25 Jun 2018  ·  22Komentar  ·  Sumber: fabric/fabric

Saya menggunakan grup threading untuk menjalankan perintah shell. Setelah menjalankan skrip yang menyertakan sleep , terminal lokal dibiarkan dengan stdin terlepas (tekanan tombol tidak terlihat pada baris perintah) dan terminal harus direset.

Saya sudah mencoba ini beberapa kali dan menemukan bahwa itu hanya terjadi dengan ThreadingGroups (SerialGroups baik-baik saja). Perintah sleep dapat berada di mana saja dalam satu baris (perintah pertama, tengah, terakhir) dan dapat digabungkan dalam satu baris dengan titik koma, atau ampersand ganda. Semua perintah berjalan seperti yang diharapkan, tetapi terminal tetap dalam kondisi buruk.

Anehnya, jika proses sebelumnya keluar dengan pengecualian yang tidak tertangkap, terminal tidak akan terpengaruh.

Untuk mereproduksi:

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")

Jalankan skrip di atas. Setelah keluar, ketik sesuatu di baris perintah. Jika Anda tidak melihat output, <ctrl>+c dan ketik reset<enter> . Untuk melihat perilaku pasca-pengecualian, batalkan komentar pada baris raise , jalankan kode, beri komentar pada baris, dan jalankan dua kali lagi. Proses pertama yang berhasil akan meninggalkan terminal dalam keadaan baik. Yang kedua akan meninggalkan stdin terlepas.

Saya menemukan masalah ini dengan sleep dalam pengujian saya, tetapi mungkin saja perintah lain memiliki efek yang sama. Ada juga kemungkinan saya hanya melakukan sesuatu yang salah. Jika itu masalahnya, saya minta maaf.

Pengaturan saya:
python 3.6.4
kain 2.1.3
OSX 10.13.5, menghubungkan ke Ubuntu 14.04

Bug Needs investigation

Semua 22 komentar

Lihat #1814 sebagai kasus masalah kedua yang dapat direproduksi.

Ini terdengar seperti bug yang sah bagi saya dan saya tidak yakin apa yang menyebabkannya begitu saja. Baunya seperti itu bisa menjadi masalah Unix generik dengan pipa terminal yang dilampirkan ke beberapa subproses sekaligus, atau (terutama dengan contoh # 1814) kondisi balapan di sekitar status pipa, atau sesuatu seperti itu.

Akan mencoba mereproduksi dan mengacaukan penyebab/solusi.

Juga, ini mungkin memerlukan perbaikan pada tingkat Invoke dan mungkin murni dalam domainnya (sejauh saya belum melakukan banyak hal dengan threading dalam konteks Invoke murni; tetapi lihat misalnya pyinvoke/invoke#194 - itu adalah hal yang harus terjadi di sana juga). Dalam hal ini saya akan memindahkan ini ke tiket di sana & "perbaikan" Fabric akan meningkatkan Invoke seseorang setelah perbaikan dirilis.

Saya menggunakan Ubuntu 16.04.2 yang terhubung ke yang sama.

Laporan lain dari masalah yang sama di #1829. Ini adalah tonggak perbaikan bug saya berikutnya dan saya akan fokus pada hari OSS yang mudah-mudahan berikutnya (Senin).

Saya baru saja mencoba mereproduksi ini (cabang 2.0, Python 3.6.4, macOS 10.12) dan sayangnya tidak dapat. Pertama mencoba double-localhost, lalu dua instance cloud jarak jauh yang terpisah, tidak ada dadu; terminal saya baik-baik saja setelah itu.

Akan mencoba sedikit wadah Linux untuk berjaga-jaga jika itu membantu, tetapi karena OP juga ada di macOS, tidak yakin itu akan membuat perbedaan. Saya juga akan mencoba menjalankannya dalam satu lingkaran untuk melihat apakah itu hanya repro sesekali.

Saya juga akan mencobanya di 2.1 jika kami entah bagaimana memperkenalkannya di 2.1, meskipun ini tampaknya sangat tidak mungkin.

@jensenak @nicktimko apakah Anda mereproduksi ini 100% setiap saat? 50%? 5%?

@bitprophet pada 2.1.3 itu terjadi dalam alur kerja saya yang sebenarnya cukup sering (>80%, saya juga pergi secara paralel ke 6 server, bukan 2), meskipun dalam contoh yang saya buat dari #1814 itu jauh lebih rendah, mungkin 20%. Saya dapat mencoba membuat pengaturan Docker, atau gagal membuat pengaturan Vagrant untuk repro.

@bitprophet Ini sudah 100% dari waktu saya. Untuk memastikan, saya memulai virtualenv baru dengan hanya kain yang diinstal. Saya menguji 2.0, 2.1, dan 2.2. Kode contoh yang saya tempel menghasilkan perilaku yang dijelaskan setiap kali. Dalam semua tes, saya terhubung ke remote Ubuntu 14.04.

Saya menggunakan versi OSX yang berbeda (10.13). Mungkin itu terkait? Padahal @nicktimko tidak ada di OSX sama sekali.

Jika versi lain menjadi masalah, inilah tampilan pip freeze di virtualenv saya:

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

Melihat semua ini diinstal sebagai dependensi fabric 2.2, saya berharap versi Anda akan terlihat serupa.

Jika ada lebih banyak yang bisa saya lakukan untuk membantu, saya lebih dari bersedia. Hanya tidak benar-benar yakin di mana lagi untuk mencari.

Komit apa yang harus saya uji; apakah Anda membuat perubahan baru-baru ini yang mungkin memengaruhi banyak hal? Saya akan mencoba dengan pembekuan di atas, Anda juga dapat memberikan reqs.txt beku lainnya dan saya dapat melihat apakah itu berhasil/tidak untuk saya.

@nicktimko @jensenak Terima kasih atas info tambahannya. Saya akan terus mencoba mengulanginya di sini; pada 20% saya pasti tidak cukup mencobanya untuk memicu. Remote saya adalah Mac dan beberapa Debian yang lebih lama, saya dapat mencoba Ubuntu Trusty jika itu spesifik untuk itu (yang akan aneh, tapi hei, semua ini aneh.)

Juga, apa lingkungan shell lokal Anda? Milik saya adalah zsh di (sekali lagi, macOS 10.12) Terminal.app bawaan, di dalam tmux. Saya juga akan mencoba beberapa permutasi di sekitar sudut itu sebentar lagi.

AHA. Ini sepertinya spesifik bash! Masih tidak dapat melakukan repro di bawah zsh di luar tmux, tetapi saat saya mencoba di bawah bash, saya segera mendapatkan gejala yang disebutkan. Ditto di dalam tmux, jadi tmux tidak ada hubungannya - ini adalah cangkang.

_Why_ ini akan berperilaku berbeda di bawah bash vs zsh, saya tidak tahu langsung. Mungkinkah spesifik tentang bagaimana penerapannya, atau (tampaknya lebih mungkin) mungkin ada sesuatu di zsh dotfiles saya yang mencegah masalah? Harus menggali ... meskipun mengidentifikasi solusi di sisi Python diperlukan dengan cara apa pun kemungkinan besar.

EDIT: juga, reproduksi terjadi bahkan ketika menghubungkan ke sshd localhost saya beberapa kali secara bersamaan, yang tidak terlalu mengejutkan. Jadi ujung jarak jauh tampaknya tidak masalah.

Juga, saya mencoba memverifikasi catatan tentang "pengecualian yang dijalankan sebelumnya kecuali mencegah masalah hanya untuk dijalankan berikutnya" tetapi itu tidak terjadi pada saya; Saya mendapatkan perilaku setiap saat terlepas.

Moar: Saya menghapus sleep untuk melihat apa yang akan terjadi; Saya masih dapat mereproduksi, meskipun sekarang sedikit lebih terputus-putus (meskipun karena ini bukan sesuatu yang mudah untuk direproduksi dalam loop otomatis, itu semua dengan reproduksi tangan, yang berarti jumlah kasus uji rendah, yang berarti % kejadian yang sebenarnya akan menjadi nyata sulit diukur secara akurat.)

Itu juga bagus, semakin sedikit pemicu yang aneh, semakin baik. Ini baunya seperti _harus_ ada kesalahan threading dasar dan bodoh di suatu tempat, yang biasanya tidak akan terpengaruh oleh apa pun yang spesifik di ujung jarak jauh atau lokal selain dari lamanya waktu membuat kondisi balapan (atau w/e) lebih mungkin.

Ingin tahu apakah ini terkait dengan pyinvoke/invoke#552 yang bermuara pada subkelas utas penanganan pengecualian Invoke (digunakan dalam ThreadingGroup di sini) mungkin telah mengacaukan deteksi kematian utas.

Harus memastikan saya mengerti bahwa (perbaikan potensialnya, pyinvoke/invoke#553, bukan penggabungan insta karena tampaknya aneh bahwa kami mendapatkan sesuatu yang tampaknya berfungsi, sangat salah) dan kemudian melihat apakah menerapkannya membuat gejala ini hilang.

Saya menghapus tidur untuk melihat apa yang akan terjadi; Saya masih dapat mereproduksi, meskipun sekarang sedikit lebih terputus-putus

Kedengarannya seperti kasus uji yang saya miliki, di mana saya perlu memukulnya beberapa kali sebelum disadap. Sepertinya Anda memiliki pegangan yang bagus untuk itu

Saya perhatikan hari ini bahwa saya juga tidak dapat mereproduksi perilaku Pengecualian yang telah saya jelaskan sebulan yang lalu ... sayangnya saya tidak ingat apa yang saya lakukan saat itu. :/

Saya memang menjalankan bash di sini. Temuan yang bagus. Fakta bahwa masalahnya terputus-putus tanpa tidur membuat saya bertanya-tanya apakah ini semacam kondisi balapan.

Anda mengatakan itu, tetapi sekarang saya tidak dapat mengulanginya lagi, atau setidaknya SANGAT terputus-putus. Menempatkan kembali tidur membuatnya lebih sering muncul. Harus menyukai kondisi balapan.

Melihat masalah Invoke itu, reporter bahkan menyebut terminal yang kacau sebagai gejala; tapi anehnya saya tidak dapat mereproduksi gejala _that_ bahkan di bawah bash, dengan kodenya. Masih tidak akan terkejut jika akar penyebabnya sama (berkaitan dengan beberapa hal seputar kematian utas dan stdin ditutup, atau mungkin disetel kembali ke buffering baris, benar sebelum keluar).

Memeriksa tempat-tempat masalah lain yang disebutkan, terhadap kasus repro di sini:

  • bit ExceptionHandlingThread.is_dead tampaknya tidak masalah, itu muncul mungkin benar, yang masuk akal karena dimaksudkan untuk menangani pengecualian di utas dan tidak satu pun dari kasus ini yang benar-benar menangani pengecualian. is_dead adalah False untuk semua 3 utas pekerja (stdin/out/err) ketika saya mengharapkannya.
  • pernyataan bahwa kita tidak menutup subproses dengan benar' stdin terasa lebih dekat dengan sasaran; jika itu membuat stdin terminal pengontrol terpasang ke deskriptor file yang sekarang sudah mati atau sesuatu ...? (Saya benar-benar harus tahu lebih baik apa yang terjadi dalam kasus ini.)

    • Kecuali...dalam kasus Fabric, tidak ada subproses lokal dan tidak ada passthrough langsung dari deskriptor file, jadi itu tidak mungkin terjadi.

    • Berarti masalahnya lebih cenderung menjadi sesuatu yang lain?


Mencoba taktik lain ... bagaimana sebenarnya dengan lingkungan terminal setelah bug muncul, telah berubah? Menjalankan stty -a bawah bash baik dengan dan tanpa adanya korupsi bug, perbedaan yang dapat saya lihat adalah:

  • lflags : terminal yang disadap memiliki -icanon , -echo , -pendin (vs istilah reguler di mana semuanya tidak memiliki tanda minus). Tidak bergema tentu tampak seperti masalah, dengan asumsi itulah artinya.
  • iflags : bugged-out memiliki -ixany dan ignpar (contoh pertama dari sesuatu yang disetel, tidak disetel, dalam pengaturan yang buruk)
  • oflags dan cflags identik, seperti juga cchars (Saya akan sangat aneh jika karakter kontrol telah berubah ...)

Menurut man stty :

  • icanon mengontrol pemrosesan ERASE dan KILL; mungkin bukan perbedaan besar (mengapa ini disetel atau tidak disetel mungkin menarik)
  • echo apa bunyinya, apakah akan di-echo, dan jelas merupakan masalah praktis terbesar dari bug tersebut.
  • pendin menyatakan apakah input (dengan asumsi stdin) tertunda setelah sakelar kanonik (dan karena icanon dengan jelas dibalik...yea) dan akan dimasukkan kembali ketika pembacaan menjadi tertunda atau lebih banyak input tiba. Tidak jelas mengapa ini penting, atau mengapa ini disetel secara normal dan tidak disetel saat disadap (saya mengharapkan yang terakhir, jika ada.)
  • ixany memungkinkan karakter apa pun untuk 'memulai output' (dan ketika tidak disetel, hanya mengizinkan MULAI. ok?)
  • ignpar berarti mengabaikan (atau tidak disetel, tidak mengabaikan) karakter dengan kesalahan paritas.

Secara keseluruhan rasanya seperti beberapa 'mode' tingkat yang lebih tinggi sedang diterapkan ke terminal, mirip dengan bagaimana kita mengatur stdin ke pembacaan karakter-buffer untuk membiarkan kita membaca 1 byte pada satu waktu alih-alih menunggu sampai pengguna masuk.

Yang terdengar seperti perilaku yang ditampilkan (semacam ...), dan yang saya ingin tahu sebelumnya; tetapi membaca kode yang dimaksud (karena tambalan Invoke menyebutkannya juga, meskipun re: thread death), perubahan mode diutarakan sebagai contextmanager, jadi _harus_ selalu menjadi tidak disetel terlepas dari bagaimana kita keluar dari loop itu. Tapi aku harus memeriksanya tiga kali sekarang.

Minor: cukup dengan mengatakan stty echo untuk menyetel echo sudah cukup untuk 'memperbaiki' terminal; bahkan jika icanon , pendin dll masih belum disetel. Tidak terlalu membantu tapi hei, bagus untuk tahu kurasa.

OKE! Saya pikir saya menemukan jawabannya, sambil menatap manajer konteks itu: itu mungkin karena manajer konteks memotret keadaan terminal saat ini untuk pemulihan pada penutupan blok. Tapi apa yang kita lakukan dalam kasus ini? Kami menjalankan _dua utas tingkat tinggi yang terpisah_, yang masing-masing menjalankan _salinan_ sendiri dari pengelola konteks ini!

Dan di Invoke, meskipun kami bermaksud untuk menjadi threadsafe, saat ini kami tidak menguji apa pun kecuali thread IO tingkat rendah kami sendiri; 99% dari "keamanan utas" hanyalah penggunaan status objek mandiri alih-alih status modul global Fabric 1 yang mengerikan. Jadi bagian tertentu dari state-keeping ini tidak pernah berjalan bersamaan dengan dirinya sendiri (sebagian karena "state" secara harfiah adalah terminal pengendali, yang hanya ada satu, jadi...negara global...).

Saya belum 100% membuktikannya (akan) tetapi tidak mungkin ini bukan. Utas yang berjalan kedua kemungkinan besar akan memotret atribut terminal pengontrol _setelah_ utas pertama telah mengaturnya ke mode buffer-karakter; kemudian, jika utas kedua itu juga _menyelesaikan_ detik (sekali lagi, mungkin tetapi tidak pasti) itu "memulihkan" keadaan buruk, secara efektif membatalkan pemulihan utas pertama.

Dikonfirmasi bahwa flag ECHO, misalnya, pasti sedang di-snapshot oleh pengelola konteks non-pertama, kemudian dipulihkan oleh yang sama. Bekerja pada solusi, yang saya pikir akan berakhir hanya menjadi "mencoba mencari tahu apakah setcbreak terlihat sudah diterapkan, dan tidak ada operasi dalam kasus itu alih-alih melakukan tarian snapshot-modify-restore".

Seharusnya memiliki efek yang diinginkan, sedikit lebih bersih untuk boot (tidak pernah menjalankan setcbreak> 1 kali) dan menghindari kasus sudut di mana perbaikan naif mungkin selalu hanya mengatur ECHO, dll ke "on" - yang akan rusak dalam situasi di mana aliran yang dimaksud adalah seperti tty tetapi _sudah_ disetel agar tidak bergema. (Tidak mungkin, tentu saja, tapi mungkin bukan tidak mungkin.)

Karena ini adalah masalah Invoke-only, saya akan memberikannya tempat di pelacak itu - saya berharap untuk menyelesaikan tes dan perbaikan untuk ini segera, tetapi jika Anda memiliki hal lain untuk ditambahkan, silakan kunjungi https ://github.com/pyinvoke/invoke/issues/559

Agar jelas, setelah diperbaiki, itu harus keluar di Invoke 1.0.2/1.1.1 (dan mungkin 1.2.0 jika saya mengeluarkannya pada saat yang sama) dan _no_ Fabric upgrade harus diperlukan, hanya Invoke.

@bitprophet Hebat! Ini berfungsi setelah memutakhirkan Invoke :)
Terima kasih atas usaha Anda.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat