运行 libreoffice 即服务

Running libreoffice as a service

我正在构建一个 Web 应用程序,除其他外,它执行文件从 doc 格式到 pdf 格式的转换。

我一直在使用与 Web 应用程序安装在同一台服务器上的 LibreOffice。通过从我的 Web 应用程序代码中提取并调用 libreoffice 二进制文件,我能够成功转换文档。

问题:当我的 web 应用程序在很短的时间内(例如毫秒)收到几个 doc->pdf 转换的 HTTP 请求时,调用 libreoffice无法一次启动多个实例。这导致一些文件被成功转换,而另一些则没有。

我认为这个问题的解决方案是这样的:

  1. 启动libreoffice服务一次,确保它接受连接,
  2. 在我的网络应用程序中处理 HTTP 请求时,与 运行 libreoffice 服务对话,要求它执行文件格式转换,
  3. "talking" 部分可以通过 shelling out 到一些 CLI 工具,或者通过一些其他方式,比如发送 libreoffice API 请求到端口或套接字文件)。

经过一些研究,我找到了一个名为 jodconverter. From it, I can use jodconverter-cli to convert the files. The conversion works, but unfortunately jodconverter will stop the libreoffice server after conversion is performed (there's an open issue 的 CLI 工具)。我看不到关闭此行为的方法。

或者,我正在考虑以下选项:

  1. 在我的网络应用程序中,确保所有转换请求都已排队;这显然会破坏并发性,例如我的用户将不得不等待他们的文件被转换,

  2. 进一步研究并使用名为 UNO 的东西,但是我使用的语言 (Elixir) 没有绑定,而且我似乎看不到手动构建 UNO 负载的方法。

如何使用 libreoffice 作为使用 UNO 的服务?

我最终选择 an advice 并行启动多个 libreoffice 实例。这通过添加 -env:UserInstallation=file:///tmp/... 命令行变量来实现:

libreoffice -env:UserInstallation=file:///tmp/delete_me_#{timestamp} \
            --headless \
            --convert-to pdf \
            --outdir /tmp \
            /path/to/my_file.doc

在对 GitHub 上名为“Parallel conversions and synchronization”的问题的长时间讨论中发现了该建议。

JODConverter 项目提供了 3 个示例项目,它们是处理转换请求的 Web 应用程序。参见 here for more information. These 3 samples use the Java Library instead of the Command Line Tool

使用Java库时,可以通过设置多个port numbers.

在应用程序启动时启动多个office进程
// This example will use 4 TCP ports, which will cause
// JODConverter to start 4 office processes when the
// OfficeManager will be started.
OfficeManager officeManager =
    LocalOfficeManager.builder()
        .portNumbers(2002, 2003, 2004, 2005)
        .build();

上面的示例可以同时处理 4 次转化。 JODConverter 管理一个内部办公流程池,您可以 configure 根据需要选择一些选项。

因此,根据您的描述,我认为您可以通过适当的配置使用 JODConverter。它可能会提高您的应用程序的性能,因为不会为每次转换启动 libreoffice。

我对 Elixir 不熟悉,但也许 this 能帮上忙?

我在尝试构建涉及以下内容的 Web 服务时遇到了与您相同的问题 pptx转pdf。看来 libreoffice 不能处理并发 要求很好。一些请求将失败而没有结果。我的解决方案是 使 pptx 到 pdf 处理一个单独的服务,并将其部署到多个 docker 个容器。当请求到来时,我们会将请求分发给 这些容器。它适用于我们的用例。