Como descobrir quando o subprocesso terminou depois de usar os.kill ()?
Eu tenho um programa Python (precisamente, um aplicativo Django) que inicia um subprocesso usandosubprocess.Popen
. Devido a restrições de arquitetura do meu aplicativo, não consigo usarPopen.terminate()
para terminar o subprocesso ePopen.poll()
para verificar quando o processo foi finalizado. Isso ocorre porque não consigo manter uma referência ao subprocesso iniciado em uma variável.
Em vez disso, tenho que escrever o id do processopid
para um arquivopidfile
quando o subprocesso é iniciado. Quando eu quero parar o subprocesso, eu abro estepidfile
E useos.kill(pid, signal.SIGTERM)
para pará-lo.
Minha pergunta é: Como posso saber quando o subprocesso foi realmente encerrado? Usandosignal.SIGTERM
precisa de aproximadamente 1-2 minutos para finalmente terminar depois de chamaros.kill()
. Primeiro eu pensei queos.waitpid()
seria a coisa certa para esta tarefa, mas quando eu chamo depoisos.kill()
isso me dáOSError: [Errno 10] No child processes
.
A propósito, estou iniciando e parando o subprocesso de um template HTML usando dois formulários e a lógica do programa está dentro de uma view do Django. A exceção é exibida no meu navegador quando meu aplicativo está no modo de depuração. Provavelmente também é importante saber que o subprocesso que eu chamo na minha opinião (python manage.py crawlwebpages
) chama outro subprocesso, ou seja, uma instância de um rastreador Scrapy. Eu escrevo opid
desta instância Scrapy para opidfile
e é isso que eu quero terminar.
Aqui está o código relevante:
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
O que eu posso fazer? Muito obrigado!
EDITAR:
De acordo coma grande resposta dado porJacek Konieczny, Eu poderia resolver meu problema mudando meu código na função_stop_crawler(request)
para o seguinte:
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