Как запустить подпроцесс 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 8

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.')

Библиотеки: