Как запустить подпроцесс pdftk, находясь в wsgi? - PullRequest
8 голосов
/ 25 сентября 2011

Мне нужно запустить процесс 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» остается как дескриптор открытого файла нулевой длины.

Я попробовал нескольковарианты вызова подпроцесса (а также простой старой os.system) - установка stdin / stdout / stderr в PIPE или в разные дескрипторы файлов ничего не меняет.Использование «shell = True» предотвращает зависание proc.communicate(), но затем pdftk не может создать выходной файл, как в devserver, так и в mod_wsgi. Это обсуждение , по-видимому, указывает на то, что с сигналами ОС и pdftk может происходить более глубокое вуду, которое я не понимаю.

Есть ли обходные пути, чтобы заставить вызов подпроцесса, как этот, работатьправильно под wsgi?Я избегаю использовать PyPDF для объединения файлов pdf, потому что мне приходится объединять достаточно большое количество файлов (несколько сотен), чтобы ему не хватало памяти (PyPDF должен сохранять все исходные файлы pdf открытыми в памяти при их объединении).

Я делаю это под последние Ubuntu, питоны 2.6 и 2.7.

Ответы [ 2 ]

8 голосов
/ 25 сентября 2011

Попробуйте использовать абсолютные пути файловой системы для входных и выходных файлов. Текущий рабочий каталог в Apache не будет тем же каталогом, что и сервер запуска, и может быть чем угодно.


Вторая попытка после устранения очевидного.

Программа pdftk - это Java-программа, которая полагается на возможность генерировать / принимать сигнал SIGPWR для запуска сборки мусора или выполнения других действий. Проблема заключается в том, что в Apache / mod_wsgi в режиме демона сигналы блокируются в потоках обработчика запросов, чтобы гарантировать, что они принимаются только основным потоком, который ищет события триггера завершения процесса. Когда вы разветвляете процесс для запуска pdftk, он, к сожалению, наследует заблокированную сигма от потока обработчика запросов. Следствием этого является то, что он препятствует работе процесса сборки мусора Java и вызывает сбой pdftk странным образом.

Единственное решение для этого - использовать Celery и сделать так, чтобы интерфейс отправлял задание в очередь Celery для celeryd, чтобы затем разветвляться и выполнять pdftk. Поскольку тогда это делается из процесса, созданного отдельно от Apache, у вас не возникнет этой проблемы.

Для более подробной информации Google для mod_wsgi и pdftk, в частности, в группах Google.

http://groups.google.com/group/modwsgi/search?group=modwsgi&q=pdftk&qt_g=Search+this+group

0 голосов
/ 24 марта 2017

Обновление: объединение двух PDF-файлов вместе с помощью Pdftk на Python 3:

Прошло несколько лет с тех пор, как этот вопрос был опубликован. (2011). В оригинальном плакате говорилось, что os.system не работало для них, когда они работали с более старыми версиями python:

  • Python 2,6 и
  • Python 2,7

Вкл. Python 3.4 , os.system работал для меня:

  • import os
  • os.system ("pdftk" + template_file + "fill_form" + data_file + "output" + export_file )

Python 3.5 добавляет subprocess.run

  • subprocess.run ("pdftk" + file_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.')

Библиотеки:

...