Как узнать, когда подпроцесс завершился после использования os.kill ()?
У меня есть программа на Python (точнее, приложение Django), которая запускает подпроцесс, используяsubprocess.Popen
, Из-за ограничений архитектуры моего приложения я не могу использоватьPopen.terminate()
завершить подпроцесс иPopen.poll()
чтобы проверить, когда процесс завершился. Это потому, что я не могу хранить ссылку на запущенный подпроцесс в переменной.
Вместо этого я должен написать идентификатор процессаpid
в файлpidfile
когда начинается подпроцесс. Когда я хочу остановить подпроцесс, я открываю этотpidfile
и использоватьos.kill(pid, signal.SIGTERM)
чтобы остановить это.
Мой вопрос: Как я могу узнать, когда подпроцесс действительно завершился? С помощьюsignal.SIGTERM
для завершения звонка требуется примерно 1-2 минутыos.kill()
, Сначала я подумал, чтоos.waitpid()
было бы правильным для этой задачи, но когда я позвоню послеos.kill()
это дает мнеOSError: [Errno 10] No child processes
.
Кстати, я запускаю и останавливаю подпроцесс из шаблона 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
Что я могу сделать? Большое спасибо!
РЕДАКТИРОВАТЬ:
Согласно сотличный ответ даноЯцек КонечныЯ мог бы решить мою проблему, изменив код в функции_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