I’ve been writing a micro service that will generate PDF files from latex
templates. I’m writing this service with phoenix and I have a working version.
Currently, I have a pretty simple workflow:
POST to /api/documents template name and template variables
The server finds the template
The server applies the template variables to the template
The server runs the template string though xelatex
The server finds the produced file
The server’s controller makes a send_file call with the PDF file path
The client server receives the file download and passes it on to the user
This is a sequential workflow. The only concurrency is provided by phoenix taking multiple requests. The problem is that a single request can take up to 4 seconds from an end users perspective. I wanted to get some advice about host to speed this up a little. The only idea I have is break the single POST call into a POST that would return an ID and then a GET to pass the ID and then receive the download. This doesn’t seem like it would speed the process up but I haven’t benchmark-ed the idea.
A few other fact may also be useful.
The client server is a GraphQL API so I don’t think I can redirect the end user to the PDF service
The GraphQL server is built in rails
Since it is a GraphQL API when it receives the file data I run the binary through base64 encode. Once again I don’t think I can do a send_file function thorough a GraphQL API
I have looked at the iona project on hex but it looks like it’s not ready to be used in production. I do plan to see if I can contribute back to it once I have a better idea of the problem space
What’s the server doing at that time. If all it does is creating the pdf and hardly anything else you can’t make it faster besides finding a faster pdf generator. From your explanations I’d even expect that the pdf generation part takes the better part of the whole request time as the other stuff should really be quite quick.
I’d do something where I return a 202 accepted with a reference/id to the client. The client builds an “inactive” document. Then when processing is completed, you can push a notification with the information to update the display with the newly created resource. It’s not faster, but it seems faster to the client.
Another benefit is that if the response from this microservice is part of a larger GraphQL response (possibly from other services), then this PDF generation will not hold up the rest of the response.
How is the call into xelatex done? If you’re starting up a new shell/xelatex process each time than this is perhaps something that you could improve by keeping an instance of xelatex already running and just piping data through to it.
Also you probably want to make sure that you do some benchmarking so that you understand the failure modes of this system, it seems likely that you a naive approach (that doesn’t limit the number of simultaneous calls into xelatex) may result in overloading the operating system’s memory.
Yes, I am taking the naive approach to start with. As time goes on I want to implement a GenStage solution where the xelatex process can demand as needed.