を使用してサブプロセスを開始するPythonプログラム(正確にはDjangoアプリケーション)がありますsubprocess.Popen
。アプリケーションのアーキテクチャ上の制約によりPopen.terminate()
、サブプロセスを終了しPopen.poll()
たり、プロセスがいつ終了したかを確認したりするために使用することはできません。これは、開始されたサブプロセスへの参照を変数に保持できないためです。
代わりに、サブプロセスの開始時にプロセスIDpid
をファイルに書き込む必要がありますpidfile
。サブプロセスを停止したい場合は、これを開いてpidfile
使用os.kill(pid, signal.SIGTERM)
して停止します。
私の質問は、サブプロセスが実際に終了したことをどのように確認できますか?signal.SIGTERM
を呼び出してから最終的に終了するには、使用に約1〜2分かかりos.kill()
ます。最初はそれos.waitpid()
がこのタスクにとって正しいことだと思いましたが、os.kill()
それが私に与えられた後にそれを呼び出すとOSError: [Errno 10] No child processes
。
ちなみに、私は2つのフォームを使用してHTMLテンプレートからサブプロセスを開始および停止しており、プログラムロジックはDjangoビュー内にあります。アプリケーションがデバッグモードの場合、例外がブラウザに表示されます。python manage.py crawlwebpages
ビュー( )で呼び出すサブプロセス自体が別のサブプロセス、つまりScrapyクローラーのインスタンスを呼び出すことを知っておくこともおそらく重要です。pid
このScrapyインスタンスのをに書き込みpidfile
ます。これが終了したいものです。
関連するコードは次のとおりです。
def process_main_page_forms(request):
if request.method == 'POST':
if request.POST['form-type'] == u'webpage-crawler-form':
template_context = _crawl_webpage(request)
elif request.POST['form-type'] == u'stop-crawler-form':
template_context = _stop_crawler(request)
else:
template_context = {
'webpage_crawler_form': WebPageCrawlerForm(),
'stop_crawler_form': StopCrawlerForm()}
return render(request, 'main.html', template_context)
def _crawl_webpage(request):
webpage_crawler_form = WebPageCrawlerForm(request.POST)
if webpage_crawler_form.is_valid():
url_to_crawl = webpage_crawler_form.cleaned_data['url_to_crawl']
maximum_pages_to_crawl = webpage_crawler_form.cleaned_data['maximum_pages_to_crawl']
program = 'python manage.py crawlwebpages' + ' -n ' + str(maximum_pages_to_crawl) + ' ' + url_to_crawl
p = subprocess.Popen(program.split())
template_context = {
'webpage_crawler_form': webpage_crawler_form,
'stop_crawler_form': StopCrawlerForm()}
return template_context
def _stop_crawler(request):
stop_crawler_form = StopCrawlerForm(request.POST)
if stop_crawler_form.is_valid():
with open('scrapy_crawler_process.pid', 'rb') as pidfile:
process_id = int(pidfile.read().strip())
print 'PROCESS ID:', process_id
os.kill(process_id, signal.SIGTERM)
os.waitpid(process_id, os.WNOHANG) # This gives me the OSError
print 'Crawler process terminated!'
template_context = {
'webpage_crawler_form': WebPageCrawlerForm(),
'stop_crawler_form': stop_crawler_form}
return template_context
私に何ができる?どうもありがとうございます!
編集:
Jacek Koniecznyのすばらしい回答によると、関数のコードを次のように変更することで、問題を解決できました。_stop_crawler(request)
def _stop_crawler(request):
stop_crawler_form = StopCrawlerForm(request.POST)
if stop_crawler_form.is_valid():
with open('scrapy_crawler_process.pid', 'rb') as pidfile:
process_id = int(pidfile.read().strip())
# These are the essential lines
os.kill(process_id, signal.SIGTERM)
while True:
try:
time.sleep(10)
os.kill(process_id, 0)
except OSError:
break
print 'Crawler process terminated!'
template_context = {
'webpage_crawler_form': WebPageCrawlerForm(),
'stop_crawler_form': stop_crawler_form}
return template_context