# Introduction
A few years ago I was tasked with integrating OpenText Content Server with a PDF conversion tool. The conversion tool ran as a service, and could be accessed via a REST API interface.
One standout feature of the service was its implementation of long polling, which is a technique where the client initiates a request and holds the connection open until new data is available. In contrast to conventional polling methods —where the client repeatedly sends requests at fixed intervals— long polling minimizes network traffic and ensures the client receives real-time updates.
In this context, the client issues a job status request, and instead of receiving an immediate response, the connection remains open until the server signals the job is complete. This means the client is immediately notified when the PDF is ready for download.
The challenge, however, is that long polling doesn't align well with the architecture of OpenText Content Server. Content Server processes network requests synchronously, which means that while a request is awaiting a response, the associated thread is blocked from performing other tasks. This blocking behavior can lead to bottlenecks and rapidly degrade system performance.
The approach that came to mind was to delegate the PDF conversion task to a dedicated service outside of Content Server. Due to its flexibility and capabilities, a Node.js microservice quickly presented itself as an ideal candidate.
# Building a JSON-RPC Microservice
The solution we developed was a JSON-RPC microservice that runs alongside Content Server. If you're not familiar with these terms, a microservice is a service, independent of other services, which focuses on a particular responsibility. A JSON-RPC microservice is a microservice that communicates over the JSON-RPC (opens new window) protocol (the protocol is somewhat irrelevant, but I needed to use something that Content Server could easily handle).
The service is a Node.js application running the Fastify web framework (opens new window), with an extension for handling JSON-RPC requests. It works as follows:
- Content Server requires a document be converted to PDF.
- A task is queued in a Content Server database table (for tracking, context, and auditing purposes).
- The task is delegated to the microservice via a network request using the JSON-RPC protocol. The request contains all the information the microservice requires to manage the task and make a completion callback request to Content Server.
- The request returns immediately, which frees up the Content Server thread to process other requests. The document is reserved and the task is put into a pending state.
- The microservice sends the job to the PDF conversion service, and does a long poll until it completes (Node.js is great for long polling due to its asynchronous nature).
- The microservice receives the completed task, and makes a JSON-RPC callback request to Content Server with the result of the conversion.
- Content Server consumes the resulting PDF, marks the task as complete, and unreserves the document.
- An agent process monitors the queue for orphaned tasks (old tasks that have not received a response), and handles them accordingly.
The key point is that no Content Server thread is blocked while the PDF is being created. The server is free to handle other tasks, and the PDF is made available to Content Server as soon as it's ready. This non-blocking approach ensures a smooth workflow without tying up resources unnecessarily.
We've been running this solution for about a year, and it's proven to be reliable, efficient, and cost effective.
# Other Uses
The solution uses a plugin architecture, which permits the microservice to be extended for other tasks. For simpler tasks, it supports synchronous execution, which delivers an immediate response for Content Server to act on.
The microservice approach creates many possibilities thanks to the large collection of Node.js packages available. Here are some possibilities to spark ideas:
- Generate responsive emails with mjml (opens new window).
- Render Markdown as HTML or PDF.
- Send a document to DeepL (opens new window) for translation.
- Send a request to ChatGPT (opens new window) to assist with content generation.
- Parse a CSV file with csv-parse (opens new window)
- Generate or manipulate Office documents with officegen (opens new window).
- Create Excel documents with exceljs (opens new window) (no more fumbling with ExcelML or clunky report tags).
- Generate PDFs with Puppeteer (opens new window).
- Run multiple complex database queries in parallel to streamline data processing.
- Enable browsers to connect directly to the microservice and receive real-time updates via server-sent events (opens new window). This could provide users with immediate feedback on long running Content Server tasks without constant polling.
- Generate a QRCode (opens new window).
- Perform image manipulation with Sharp (opens new window).
- Send push notifications with web-push (opens new window).
- etc.
It's been an interesting project, and I look forward to seeing what other problems we can solve with the design.