最近、Ubuntu 12.04 を実行する従来のマシンから Ubuntu 18.04 を実行する Google Cloud インスタンスに開発インフラストラクチャを移行しました。
開発者は通常、いくつかの画面を起動し、これらの画面でdjangoサーバーを実行します。
たとえば、画面を作成し、screen -S webserver_5552
画面内でdjango開発アプリケーションを実行できます。python manage.py runserver 0.0.0.0:5552
以前のコンピュータでは、screen(ctrl+a d
)を切り離してscreen -r xxxx.webserver_5552
後で返す()できました。 djangoサーバープロセスはまだここにあり、実行中であり、screenのbashプロセスによって所有されています。
しかし、Google Cloud マシンではこれが異なる動作をし、私たちを狂わせました。それでも画面を切り離すことができますが、後で戻ってくると、djangoプロセスはもはやbashプロセスに属しなくなります!代わりにinitプロセスが所有しています(ppidはpsから1に設定されています)。
通常、私たちはdjangoプロセスがシグナルを受け取り、所有権を変更する前にトレースバックを取得します。しかし、それが私たちが得るすべてであり、根本的な原因が何であるか、それを防ぐ方法を理解することはできません。
Traceback (most recent call last):
File "manage.py", line 65, in <module>
execute_from_command_line(sys.argv)
File "/home/testing/env/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 367, in execute_from_command_line
utility.execute()
File "/home/testing/env/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 359, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/home/testing/env/local/lib/python2.7/site-packages/django/core/management/base.py", line 294, in run_from_argv
self.execute(*args, **cmd_options)
File "/home/testing/env/local/lib/python2.7/site-packages/django/core/management/commands/runserver.py", line 58, in execute
super(Command, self).execute(*args, **options)
File "/home/testing/env/local/lib/python2.7/site-packages/django/core/management/base.py", line 345, in execute
output = self.handle(*args, **options)
File "/home/testing/env/local/lib/python2.7/site-packages/django/core/management/commands/runserver.py", line 97, in handle
self.run(**options)
File "/home/testing/env/local/lib/python2.7/site-packages/django/core/management/commands/runserver.py", line 106, in run
autoreload.main(self.inner_run, None, options)
File "/home/testing/env/local/lib/python2.7/site-packages/django/utils/autoreload.py", line 333, in main
reloader(wrapped_main_func, args, kwargs)
File "/home/testing/env/local/lib/python2.7/site-packages/django/utils/autoreload.py", line 304, in python_reloader
exit_code = restart_with_reloader()
File "/home/testing/env/local/lib/python2.7/site-packages/django/utils/autoreload.py", line 290, in restart_with_reloader
exit_code = os.spawnve(os.P_WAIT, sys.executable, args, new_environ)
File "/home/testing/odesk_android/../env/lib/python2.7/os.py", line 575, in spawnve
return _spawnvef(mode, file, args, env, execve)
File "/home/testing/odesk_android/../env/lib/python2.7/os.py", line 548, in _spawnvef
wpid, sts = waitpid(pid, 0)
OSError: [Errno 4] Interrupted system call
これは特に迷惑な動作であり、根本的な原因を特定することはできません(Ubuntu、GCP、一部の不適切な設定などに起因するものか…?)。
編集する:
スプラッシュ画面とスプラッシュ画面でテストしました。
testing@whova-qa-01:/home/simon_ninon_whova_com$ ps -ejf | grep 55530
testing 20764 19638 20764 19638 4 00:12 pts/18 00:00:01 ../env/bin/python manage.py runserver 0.0.0.0:55530
testing 20769 20764 20764 19638 12 00:12 pts/18 00:00:04 /home/testing/appium_android/../env/bin/python manage.py runserver 0.0.0.0:55530
ご覧のとおり、../env/bin/python manage.py runserver 0.0.0.0:55530
PID = 20764およびPPID = 19638でdjangoプロセス(bashプロセス)を開始しました。
このdjangoプロセスは、/home/testing/appium_android/../env/bin/python manage.py runserver 0.0.0.0:55530
PID = 20769およびPPID = 20764(私が作成した元のプロセス)の子プロセスを作成しました。
今朝、もう一度コンピュータにログインすると画面を再接続する前に、すべてがまだ同じです。
simon_ninon_whova_com@whova-qa-01:~$ ps -ejf | grep 55530
simon_n+ 9026 9011 9025 9011 0 09:09 pts/9 00:00:00 grep --color=auto 55530
testing 20764 19638 20764 19638 0 00:12 pts/18 00:00:01 ../env/bin/python manage.py runserver 0.0.0.0:55530
testing 20769 20764 20764 19638 2 00:12 pts/18 00:13:56 /home/testing/appium_android/../env/bin/python manage.py runserver 0.0.0.0:55530
そのため、画面を再接続すると問題が発生するとは予想されません。しかし、画面を再接続すると、ハム、プロセスが終了します!
testing@whova-qa-01:~$ ps -ejf | grep 55530
testing 9085 9031 9084 9011 0 09:10 pts/9 00:00:00 grep --color=auto 55530
testing 20769 1 20764 19638 2 00:12 pts/18 00:13:59 /home/testing/appium_android/../env/bin/python manage.py runserver 0.0.0.0:55530
ご覧のとおり、親プロセスは終了しますが、initプロセスが所有する子プロセスはまだ存在します。
興味深いことに、元のbashプロセスがまだ存在することを確認すると、次のような結果が得られます。
simon_ninon_whova_com@whova-qa-01:~$ ps aux | grep 19638
simon_n+ 9315 0.0 0.0 14664 1016 pts/9 S+ 09:16 0:00 grep --color=auto 19638
testing 19638 0.0 0.0 25360 7692 pts/18 Ss+ Feb27 0:00 /bin/bash
したがって、画面を再接続すると、bashプロセスが保存されるように見えますが、何らかの理由で親djangoプロセスが終了します。
この段階で何を期待すべきか分からないのですか?サーバーを起動してしばらく画面を切断して再接続すると、問題は発生せず、しばらくしてから発生します。
答え1
根本原因を見つけました。
画面が再接続されると、SIGWINCH 信号が親 django プロセスに送信されます。プロセスはそれを処理できず、衝突だけが発生し、子供は孤児になります。
その後、用語のサイズを変更するか、を使用して簡単に再起動できますkill -28 PID
。
なぜGCPインスタンスでのみ発生するのかはわかりませんが、環境(Pythonバージョン?)に何か他のものがある可能性があります。とにかく、これは解決策が見つかる場所についてのより多くの手がかりを提供します。
編集する:
しばらく検索した結果、根本的な原因はreadline
ソースコードからdjangoの依存関係を取得したことでした。
python readlineはライブラリへのバインディングであり、信号処理がpython / djangoで実行される信号処理を妨げているようgnureadline
です。gnureadline
以前のシステムではなくGCPシステムでのみ発生することを考慮すると、GCPシステムに別のgnureadlineがインストールされ(バージョン側または使用されているコンパイルオプションの観点から)、信号処理の動作が異なると思われます。