Как запустить подпроцесс pdftk, находясь в wsgi?
Мне нужно запустить процесс pdftk во время обслуживания веб-запроса в Django и дождаться его завершения. Мой текущий код pdftk выглядит следующим образом:
proc = subprocess.Popen(["/usr/bin/pdftk",
"/tmp/infile1.pdf",
"/tmp/infile2.pdf",
"cat", "output", "/tmp/outfile.pdf"])
proc.communicate()
Это работает нормально, пока я выполняю под сервером dev (работает как пользователь www-data
). Но как только я переключаюсь на mod_wsgi, ничего больше не меняя, код зависает на proc.communicate()
, и " outfile.pdf " остается открытым дескриптором файла нулевой длины.
Я попробовал несколько вариантов вызова подпроцесса (а также обычный старый ос.system) -- установка stdin/stdout/stderr на канал или на различные дескрипторы файлов ничего не меняет. Использование "shell=True" предотвращает зависание proc.communicate()
, но тогда pdftk не удается создать выходной файл, как под devserver, так и под mod_wsgi. это обсуждение , кажется, указывает на то, что может быть какое-то более глубокое вуду, происходящее с сигналами ОС и pdftk, которые я не понимаю.
Существуют ли какие-либо обходные пути, чтобы заставить вызов подпроцесса, подобный этому, работать должным образом под wsgi? Я избегаю использовать PyPDF для объединять pdf-файлы, потому что я должен объединить достаточно большое количество файлов (несколько сотен), чтобы у него закончилась память (PyPDF должен держать каждый исходный pdf-файл открытым в памяти при объединении их).
Я делаю это под последними Ubuntu, pythons 2.6 и 2.7.
2 ответа:
Попробуйте использовать абсолютные пути файловой системы к входным и выходным файлам. Текущий рабочий каталог в Apache не будет таким же каталогом, как run server, и может быть любым.
Вторая попытка после устранения очевидного.
Программа pdftk-это Java-программа, которая полагается на возможность генерировать / получать сигнал SIGPWR для запуска сборки мусора или выполнения других действий. Проблема в том, что в Apache / mod_wsgi в режиме демона сигналы блокируются в пределах запросите потоки обработчиков, чтобы убедиться, что они получены только главным потоком, ищущим события триггера завершения процесса. Когда вы разветвляете процесс для запуска pdftk, он, к сожалению, наследует заблокированную сигмаску от потока обработчика запроса. Следствием этого является то, что он препятствует работе процесса сборки мусора Java и вызывает сбой pdftk странным образом.Единственное решение для этого-использовать сельдерей и заставить переднюю часть отправить задание в Сельдерей очередь для celeryd, чтобы затем развилить и выполнить pdftk. Поскольку это делается из процесса, созданного в отличие от Apache, у вас не будет этой проблемы.
Для более кровавых деталей Google для mod_wsgi и pdftk, в частности в группах Google.
Http://groups.google.com/group/modwsgi/search?group=modwsgi&q=pdftk&qt_g=Search+this+group
Update: слияние двух PDF-файлов вместе с помощью Pdftk на Python 3:
Прошло уже несколько лет с тех пор, как этот вопрос был опубликован. (2011). Оригинальный плакат гласил, что оС.system не работала для них, когда они запускали более старые версии python:
- Python 2.6 и
- Python 2.7
На Python 3.4, оС.система работала на меня:
- импорт ОС
- оС.система ("pdftk" + template_file + "fill_form" + data_file + "output" + export_file)
Python 3.5 добавляет подпроцесс .run
Подпроцесс.run ("pdftk" + template_file + "fill_form" + data_file + "output" + export_file)
Я использовал абсолютные пути для моих файлов:
- template_file = "/var / www/myproject / static / "
Я запустил это с Django 1.10, с сохранением результирующего вывода в export_file .
Как объединить два PDF-файла и отобразить вывод PDF:
from django.http import HttpResponse, HttpResponseNotFound from django.core.files.storage import FileSystemStorage from fdfgen import forge_fdf import os template_file = = "/var/www/myproject/template.pdf" data_file = "/var/www/myproject/data.fdf" export_file ="/var/www/myproject/pdf_output.pdf" fields = {} fields['organization_name'] = organization_name fields['address_line_1'] = address_line_1 fields['request_date'] = request_date fields['amount'] = amount field_list = [(field, fields[field]) for field in fields] fdf = forge_fdf("",field_list,[],[],[]) fdf_file = open(data_file,"wb") fdf_file.write(fdf) fdf_file.close() os.system("pdftk " + template_file + " fill_form " + data_file + " output " + export_file) time.sleep(1) fs = FileSystemStorage() if fs.exists(export_file): with fs.open(export_file) as pdf: return HttpResponse(pdf, content_type='application/pdf; charset=utf-8') else: return HttpResponseNotFound('The requested pdf was not found in our server.')
Библиотеки: