Jak dowiedzieć się, kiedy podproces został zakończony po użyciu os.kill ()?
Mam program w Pythonie (dokładnie aplikację Django), który uruchamia podproces za pomocąsubprocess.Popen
. Ze względu na ograniczenia architektoniczne mojej aplikacji nie mogę z niej korzystaćPopen.terminate()
zakończyć podproces iPopen.poll()
sprawdzić, kiedy proces się zakończył. Dzieje się tak, ponieważ nie mogę utrzymywać odniesienia do rozpoczętego podprocesu w zmiennej.
Zamiast tego muszę napisać identyfikator procesupid
do plikupidfile
kiedy rozpoczyna się podproces. Kiedy chcę zatrzymać podproces, otwieram topidfile
I użyćos.kill(pid, signal.SIGTERM)
zatrzymać to.
Moje pytanie brzmi: Jak mogę się dowiedzieć, kiedy podproces naprawdę się zakończył? Za pomocąsignal.SIGTERM
potrzebuje około 1-2 minut, aby ostatecznie zakończyć połączenieos.kill()
. Najpierw tak myślałemos.waitpid()
byłoby to właściwe dla tego zadania, ale kiedy zadzwonię po toos.kill()
to daje miOSError: [Errno 10] No child processes
.
Nawiasem mówiąc, uruchamiam i zatrzymuję podproces z szablonu HTML za pomocą dwóch formularzy, a logika programu znajduje się w widoku Django. Wyjątek jest wyświetlany w mojej przeglądarce, gdy moja aplikacja jest w trybie debugowania. Prawdopodobnie ważne jest również, aby wiedzieć, że podproces, który nazywam moim zdaniem (python manage.py crawlwebpages
) sama wywołuje inny podproces, a mianowicie instancję przeszukiwacza Scrapy. Piszępid
tej instancji Scrapy dopidfile
i to właśnie chcę zakończyć.
Oto odpowiedni kod:
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
Co mogę zrobić? Dziękuję Ci bardzo!
EDYTOWAĆ:
Wedługświetna odpowiedź podane przezJacek Konieczny, Mógłbym rozwiązać mój problem, zmieniając kod w funkcji_stop_crawler(request)
do następujących:
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