PDF-generatie: Een lange tocht met een succesvol einde

PDF-generatie: Een lange tocht met een succesvol einde

Als leverancier van enquêtesoftware houdt Survalyzer zich bezig met het maken van PDF-documenten om enquêtedeelnemers de mogelijkheid te bieden de gegeven antwoorden als een document te downloaden. Het document moet exact weergeven wat de gebruiker in de enquête heeft gezien. Bovendien wil een bedrijf dat deelnemers voor deelname aan een enquête heeft uitgenodigd, het PDF-document van hun eigen huisstijl voorzien. Het was een hobbelige weg met veel doodlopende wegen op weg naar een geschikte oplossing. Daarom hebben we besloten om de ervaring met betrekking tot het genereren van PDF’s te delen om zodoende ontwikkelaars en architecten bij het nemen van de juiste beslissingen te helpen.

Uitgangspunt:
Onze klanten zijn verplicht een PDF-bevestiging met de gegeven antwoorden van een enquête aan te bieden. Vooral in de overheids- en onderwijssector is het essentieel dat aan deze eis wordt voldaan. In eerste instantie hebben wij een HTML-pagina gebouwd die de gegeven antwoorden in een overzicht toont met de mogelijkheid de antwoorden door de klant te laten afdrukken. Toen dit eenmaal klaar was, werd besloten om van deze pagina aan de serverzijde een PDF-document te creëren. De beslissing werd ingegeven door het idee dat we al een weergegeven versie van de antwoorden hadden en dat we geen tweede versie wilden bouwen.

Eerste technische implementatie:

Aangezien de overzichtspagina een statisch weergegeven HTML-pagina was, werd gekozen voor een aanpak waarbij de rendermogelijkheden van de browser werden gebruikt om het PDF-document te genereren. Om ervoor te zorgen dat het document er voor alle klanten hetzelfde zou uitzien en niet van de browser van de gebruiker afhankelijk zou zijn, werd de rendering aan de serverzijde uitgevoerd. De volgende stappen werden uitgevoerd:

pdf generation process

Implementatiekwesties:

De implementatie ging vrij snel omdat we de browsermogelijkheden optimaal benutten en van een bekende bibliotheek met de naam wkhtmltopdf (https://wkhtmltopdf.org/) gebruik maakten. Deze bibliotheek nam de browser-afhandeling over. Zolang het gebruik van deze nieuwe functionaliteit gering was, zag alles er goed uit. Maar naarmate onze klanten meer en meer gebruik van PDF-rendering gingen maken, ontstonden er steeds meer problemen…

Het belangrijkste probleem was dat het hele proces erg CVE- en geheugenintensief is en slechts in beperkte mate parallel kon verlopen. Ik denk dat je je zelfs op je lokale PC kunt voorstellen wat er zou gebeuren, als je 100 browservensters zou openen. Zelfs met de beste laptop zal je besturingssysteem vastlopen. In zo’n situatie werken applicaties niet naar behoren. In feite is het op een server hetzelfde als op je lokale laptop, maar dan op een iets grotere schaal. We werden geconfronteerd met zombieachtige situaties bij browsers die het geheugen niet opnieuw vrijgaven en erger nog, die de CVE verbruikten met eindeloze loops zonder enig resultaat. De definitieve doodsteek van de oplossing was een uitval van het hele systeem die door de enorme belasting tijdens een zeer groot en niet minder belangrijk onderzoek werd veroorzaakt.

We hebben dit snel ondervangen door de PDF-rendering naar een geïsoleerde server te verplaatsen, zodat in ieder geval de prestatie van de hele webapplicatie niet meer werd beïnvloed. Tegelijkertijd hebben we onze klanten geadviseerd om het gebruik van de PDF-functionaliteit te vermijden, in ieder geval bij grote enquêtes.

Deze dag was mijn persoonlijke Waterloo, aangezien ik dit alles overnam van mijn voorganger en ik alleen in staat was om brandjes te blussen. Maar toen de rook was opgetrokken, werd mijn gretigheid gewekt om van de huidige oplossing af te komen en de best mogelijke manier te implementeren om zo onze klanten met kwalitatief goede PDF’s te bedienen en onze systemen tegen uitval te beveiligen die door de hoge belasting werd veroorzaakt.

Technische evaluatie – Gebruik van een renderbibliotheek:

De beslissing om de frontend te verplaatsen van een statisch weergegeven pagina (ASP.NET MVC) naar een enkele pagina-applicatie met behulp van de meest recente Angular Framework, was een doorbraak in het spel. We hebben verschillende bibliotheken geëvalueerd die in staat blijken te zijn om HTML als bron voor PDF-generatie te gebruiken. De kandidaten waren:

Geen van hen was in staat om onze HTML5 + CSS3 pagina’s correct weer te geven. Het resultaat was veelal een lege pagina of een beschadigde lay-out.

Evaluatieoverzicht:

Na wat onderzoek begreep ik waarom alle bibliotheken waren uitgevallen:

De DOM van de HTML bevat niet alle informatie die nodig is om de pagina correct weer te geven. De browser heeft een mechanisme dat schaduw DOM wordt genoemd en dat geen deel uitmaakt van het HTML-document. Moderne SPA-frameworks zoals Angular maken intensief gebruik van de shadow DOM om de weergave te optimaliseren. Dit resultaat bracht me terug naar de oorspronkelijke oplossing en ik probeerde een manier te vinden om de prestatieproblemen van de browser-gebaseerde oplossing aan te pakken met behulp van een moderne cloud-architectuur.

Technische evaluatie – Gebruik van Azure-functies:

De focus lag nu op het bouwen van een schaalbare browser-gebaseerde oplossing die elke willekeurige belasting aankan en met de vraag kan meegroeien. De gekozen technologie was het gebruik van NodeJS Azure-functies, gebaseerd op een Windows-image. Om met de browser om te gaan, heb ik voor de bibliotheek Puppeteer (https://pptr.dev/) gekozen. Op het eerste gezicht ziet de werkwijze er fraai en eenvoudig uit.

puppeteer source code

Lokaal werkte deze eenvoudige oplossing voor het genereren van PDF’s als een tierelier, dus besloot ik om het uit te rollen op Azure. Maar de uitgerolde versie genereerde geen PDF’s, in plaats daarvan crashte het. Na wat verder onderzoek en wat gegoogel, kwam ik erachter dat Azure Functions in een geïsoleerde sandbox-omgeving werken. De basis voor alle weergave in Windows is de GDX+ bibliotheek. Helaas is deze bibliotheek gereserveerd voor veiligheidsdoeleinden. De artikelen en whitepapers raden ontwikkelaars aan om in plaats daarvan een Linux-image te gebruiken. Ik volgde het advies op en gaf opdracht voor een Linux Azure-functie. Gelukkig was de code gebaseerd op NodeJS en was dus platformonafhankelijk. De ingebruikname en implementatie was een kwestie van minuten, maar de volgende horde kwam direct daarna.

Microsoft baseert Linux Azure functies redelijkerwijs op zogenaamde smalle images om laadtijden te verkorten en prestaties te verhogen. Dit is volkomen logisch, maar voor mijn use case ontbraken veel shared bibliotheken van Linux en zelfs het starten van een browser zonder kop werkte niet. Na nog eens verder gegoogeld te hebben, ontdekte ik dat ik niet de enige was met deze architecturale aanpak of met het probleem van ontbrekende bibliotheken. Het was duidelijk dat de standaard Linux-images voor mijn bedoeling onbruikbaar waren.

Technische evaluatie – Gebruik van Docker-containers:

Docker-containers waren de beloofde oplossing. Ik was bekend met deze technologie en had al eerder gepubliceerde containers gebruikt, maar ik had er nog nooit zelf een gebouwd. Google heeft me opnieuw geholpen om op stoom te komen en al vrij snel heb ik mijn eerste eigen container gemaakt. Als basis maakte ik gebruik van openbare sjablonen, maar ik was gretig genoeg om het volledig zelf te bouwen om de technologie en de te nemen stappen tot in de details te begrijpen. Uiteindelijk vond ik alle noodzakelijke ontbrekende pakketten en bouwde ik mijn docker-container:

docker image

Dit was de eerste aanpak die werkte. Het was vrij traag met 45 seconden voor een doorsnee document, maar het werkte tenminste.

pdf document first approach

Vergeleken met de oorspronkelijke oplossing, groeien Azure Functions mee met de vraag en met behulp van het betalen per gebruik principe kunnen we met de onvoorspelbare vraag omgaan. Ondertussen waren de volgende nieuwe eisen prangender dan voorheen.

  • De generatie van een PDF met een huisstijlsjabloon (voorblad, koptekst, voettekst)
  • De opname van een inhoudsopgave
  • De toegankelijkheid van het PDF-document

Ik probeerde aan deze extra eisen te voldoen door het reeds gecreëerde PDF- document in een sjabloondocument in te sluiten. Uiteindelijk zag het document er verschrikkelijk uit, was het helemaal niet toegankelijk en liep de rendertijd ook nog eens tot 90 seconden op. Ik heb deze poging heel kort gehouden omdat ik hiermee op een dood spoor zat; de oplossing kwam niet dichterbij. Ik ging terug naar stap 1; alles wat ik tot dusverre over de PDF-generatie wist, trok ik in twijfel.

Conclusie en definitieve oplossing:

Er is een gezegde: Het donkerste uur komt even voor de dageraad!
Achtergebleven met een onbruikbare oplossing, was ik gefrustreerd geraakt en vroeg ik me af waar ik een verkeerde afslag had genomen. Ik realiseerde me dat ik verder weg was dan ooit van mijn ambitie een uitstekende PDF-oplossing aan onze klanten te leveren.

De reflectie over wat tot deze wanhopige situatie heeft geleid, wees mij op de oplossing. De hele inspanning die tot dusverre werd gedaan, was te wijten aan het feit dat we niet handmatig een PDF-weergave voor onze enquête-elementen wilden maken. Alle frustratie was gebaseerd op de veronderstelling dat we de HTML als basis moeten nemen.

Met dat in gedachten besloot ik een andere richting in te slaan. We hadden al een werkende PDF-generatie-oplossing voor het exporteren van enquêtes. De aanpak was gebaseerd op een Word-sjabloon dat door iedere klant zelf ontworpen kon worden met inachtneming van de gestelde huisstijlvereisten. Het document hoeft alleen maar een aantal velden met placeholders te bevatten. Deze velden worden tijdens de renderfase door de echte inhoud vervangen. Met behulp van deze aanpak konden op vrij eenvoudige wijze voorpagina’s, inhoudsopgave, koptekst & voettekst en zelfs een vrijwaringsclausule op de laatste pagina worden gecreëerd. Deze aanpak hield voor onze klanten een kansrijke strategie in. De aanpak en het resulterende document voldeden aan alle eisen die ook aan de antwoorden PDF werden gesteld.

Ook het mechanisme waarmee het enquêtedocument werd doorlopen en alle nodes werden weergegeven, was al aanwezig. Twee aspecten ontbraken nog: het toevoegen van de antwoorden aan het document en de opmaak ervan. De resulterende code was natuurlijk meer dan wat nodig zou zijn geweest voor de HTML-gebaseerde aanpak, maar met ongeveer 600 regels was ik in staat om een PDF te maken die er mooi uitzag en, afhankelijk van de grootte van de enquête, in ongeveer 5 seconden kon worden gerenderd. Dit is 18 keer sneller dan de vorige aanpak, die niet eens aan alle eisen voldeed. Ook het verbruik van de CVE en het geheugen daalde drastisch omdat er geen browser meer aan te pas kwam.

Voor het opbouwen van het Word-sjabloon maken we van de Aspose Words bibliotheek gebruik. Deze bibliotheek is zeer stabiel, snel en biedt alle functies die nodig zijn om zeer geavanceerde documenten te maken, zoals aangepaste gedefinieerde stijlen en nog veel meer.

Dit is hoe het document er nu uitziet:pdf document final

Deze bibliotheek heeft ook de mogelijkheid om een document als PDF op te slaan. Aspose beschikt bovendien over de mogelijkheid om een zeer hoog niveau van toegankelijke PDF-documenten te behalen, op voorwaarde dat het door de klant aangeleverde sjabloon aan de PDF-UA-eisen voldoet. Het gegeven voorbeeld laat zien hoe een enkelekeuzevraag er op een screenreader uit zou zien:

pdf screen reader

(Bron: PDF Accessibility Checker 3)

Zoals u kunt zien, is de eerste optie Amazon aangevinkt. Het getoonde voorbeeld heeft een PDF-UA conformiteitspercentage van 96,5% (20316 van 21050 elementen). Alle elementen die niet aan de eisen voldoen, zijn decoratieve elementen zoals randen in tabellen zonder relevante inhoud.

Om met elke vraag te kunnen meeschalen, houden we de Linux-gebaseerde Azure functies aan. Uiteindelijk, na een lange tocht, beschikken we over een betrouwbare, schaalbare en eenvoudige PDF-generatie-oplossing die aan alle eisen voldoet. De conclusie is eens te meer: Eenvoud is moeilijker dan complexiteit.

Related Posts
Leave a Reply