1 Jahr Blog hinter dem Webcache

Wir haben hier natürlich für den November 2023 nur einen halben Monat, weil die Stats vom 13. des Monats sind. Eine kleine Rückschau zur Technik gibt es auch noch.

Sie verpassen nichts, sind nur Zahlen pro Monat mit einigen Balkendiagrammen.

1 Jahr Blog Zugriffszahlen

Einfach nur Zahlen veröffentlichen kann jeder, deswegen ein kleiner Bericht aus dem Jahr des Caches.

Aus dem Leben eines Webcaches

Die meiste Zeit lief das Cache problemlos, sonst hätte ich es auch nicht benutzt. Die Vorteile liegen klar auf der Hand, weil die Zugriffszeiten massiv verbessert wurden. Allerdings stieg auch der Komplexitätsgrad der Serverkonfiguration an:

– DNS Proxies
– Backend-Webserver
– Fake DNS Server
– Cacheserver

Ohne groß ins Detail zu gehen, weil mit irgendwas muß man ja sein täglich Brot verdienen ;), kommen wir zu einer Besonderheit der Konstruktion: Der Backendserver hat eine andere IP als der Cacheserver.

Weil das so ist, muß man dem Cache irgendwie mitteilen, daß eine aufgerufene Domain eine ganz andere IP hat. Dazu benutzt man einen FakeDNS Server. Der war in Perl geschrieben und besteht im Prinzip nur aus einer einzigen Schleife: „Wenn wer fragt, sagt diese IP auf“. Das dumme daran ist, es ist Perl. Perl fällt aus bzw. für den Fragenden kommt einfach ab und zu mal keine Antwort.

„Keine Antwort“ meint aber im Cache: „Hey, der DNS Server ist tod.“   Was macht ein Cache wenn der Server „tod“ ist? Genau, es entfernt den DNS aus der Liste der aktiven DNS Server. Ziemlich blöd, wenn das nur ein Server ist 🙁 Also haben wir zwei konfiguriert und das Cache sollte Roundrobin machen. Machts aber nicht, auch wenn es in der Anleitung steht 😉

d.h. ein dritter FakeDNS mußte her und da hörte der Spaß auf. Statt noch ein Perlscript zu starten, wurde named als Forwarder konfiguriert. Das antwortet jetzt immer stabil  auf Anfragen, weil es nur einmal am Tag nachfragt und geht so mit den arbeitsscheuen Perlscripten wohlwollend um.

Warum Perlscripte?

Weil um eine einzige IP auszugeben, ein vollwertiger PowerDNS nebst Datenbank vielleicht ein bisschen zu viel wäre. Dachte ich. Heute tendiere ich dazu mal entsprechend umzubauen, weil das den Komplexitätsgrad verringert und die Stabilität erhöht. Der Preis wird eine Datenbank basierte Pflege beinhalten, statt einfach ‚echo „domain.de 123.45.67.89“ >> fakedomainliste.txt‚ zu benutzen. Ein kleiner Preis, im Vergleich zum Stress durch die Ausfälle.

Wenn Ihr also plant WordPress mit einem Cache zu betreiben, dann macht es gleich richtig.

Praktischerweise konnte man aus diesem privaten Beispiel sehr viel für unsere Firma übernehmen und jetzt haben wir ein miniCloudflare, nur ohne Abhängigkeit von einer US-Firma \o/  Das reduziert die Last und macht Kunden glücklich.

PDF Dokumente auf dem Server erzeugen

Es gibt viele Wege auf einem (Web)-Server ein PDF Dokument zu erstellen, eine, die besondere Vorteile hat, möchte ich Euch heute vorstellen.

PDF Dokumente auf dem Server erzeugen

Wenn man „normalerweise“ Dokumente auf dem Server erzeugen will, so etwas wie Rechnungen, Bestellbestätigungen usw. muß man eine PDF-Lib nehmen. Mit deren Hilfe baut ein Programmierer das Dokument aus Einzelteilen zusammen, sprich, jede einzelne Linie, jeden Text und jede Schriftart. Dafür braucht er ewig lang und das bedeutet, es wird teuer.

Da Webseiten von Webentwicklern und Webdesignern gestaltet werden, wäre es doch viel besser, wenn diese Leute die Vorlagen für die Rechnungen in HTML, CSS und Javascript bauen könnten und man nur noch „die Werte“ einsetzt, oder? Genau das geht mit wkhtmltopdf und einigen anderen derartigen Programmen.

WKHTMLTOPDF

wkhtmltopdf hat den Vorteil, daß es in einer Statischen Form benutzt werden kann, ohne das man einen X11-VirtualFramebuffer braucht. Das macht den Einsatz auch auf gemieteten Webaccounts einfach.

Webdesigner können sich via HTML und CSS derart in dem Dokument austoben, wie es ein Programmierer mit der Lib fast nicht könnte und die Sache hat einen Vorteil: Man kann sich die erzeugte HTML Datei im Browser ansehen und bekommt so eine Vorschau ohne das man das PDF wirklich erzeugen und anzeigen müßte. Natürlich gibt es Stolpersteine und kleine Abweichungen vom Wunschzustand, das bleibt nicht aus. So kann man z.B. recht schlecht Seitenzahlen einfügen, außer man erzeugt die Seiten einzeln, bevor Sie ins PDF umgewandelt werden.

Beispiel:

wkhtmltopdf –print-media-type datei1.html datei2.html datei.pdf

–print-media-type gibt hier an, daß die print.css benutzt werden soll. So kann man in der Vorlage CSS fürs Web und für das PDF unterbringen. Dies erlaubt auch den einfachen Einsatz des Templates auf der Seite selbst 😉

Da wkhtmltopdf auch Javascript unterstützt, können auch dynamische PDFs erzeugt werden, die abhängig vom benutzergewählten Inhalt andere Darstellungen haben, ohne das man das großartig in der Webanwendung, die das PDF erzeugt, implementieren müßte. Das hat zur Folge, daß man bei einer geschickten Wahl des Dokumentenaufbaus, nichts an dem z.b. PHP Script machen muß, um neue Inhalte einzubauen.

Im konkreten Fall hatten wir eine SPA (Single Page Application ) gebaut, die dynamisch neue Formularinhalte hinzufügt, und damit hochgradig veränderliche Inhalte verarbeiten mußte. Das ist im PHP dann meistens die Hölle, das wieder zu sortieren, aber in unserem Fall konnten wir leicht die strukturelle Form in ein mehrseitiges PDF-Dokument überführen, ohne das das PHP Script wegen der Komplexität fehleranfällig wird oder etwas über die einzelnen Formularfelder wissen müßte, was über Basisinformationen wie Namen und Typen hinausgeht. Es lohnt sich immer eine gute Idee mal in der Praxis auszuprobieren 😉

Ghostscript

Meine Werbeagentur und ich haben diese Art der PDF Erzeugung neulich für ein Projekt benutzt, bei dem auch noch Bedingungen, für die es bereits fertige PDFs gab, in das finale Dokument eingefügt werden mußten. Dies kann man leicht mit Ghostscript erledigen, indem die einzelnen PDFs zu einem einzigen PDF verbunden werden:

gs -q -dBATCH -dNOPAUSE -sDEVICE=pdfwrite -sOutputFile=final.pdf datei.pdf bedingung1.pdf bedingung2.pdf

Natürlich könnte man die Bedingungen auch gleich als HTML Dokument in das vorher erzeugte PDF einbringen, aber in der Realität kommen solche Dokumente aus irgendwelchen Rechtsabteilungen und die können kein HTML oder CSS, sondern gerade einmal Word. Daher ist es meistens nötig, das in zwei Schritten zu realisieren.

Synapse 1.51+ mit schwerem Empfangsfehler

Marix Synapse Implementierung hat einen schweren Bug in den Versionen 1.51 und 1.52, der dazu führt, daß keine Nachrichten mit bestimmten Eigenschaften ( Verschlüsselung ) beim Empfänger ankommen.

Synapse 1.51+ mit schwerem Empfangsfehler

Kurios macht diesen Fehler, daß er nur bei Externen Nachrichten auftaucht. Schickt man intern Nachrichten von einem Account zum Anderen, kommen die Nachrichten trotzdem an.

Um festzustellen, daß Ihr betroffen seid, reicht es im Log des Homeservers nach diesen Fehlermeldungen zu suchen:

2022-02-09 00:00:41,933 - synapse.federation.transport.server.federation - 114 - ERROR - PUT-34443 - 'dict' object has no attribute 'edu_type'
Traceback (most recent call last):
  File "/usr/lib/python3.9/site-packages/twisted/internet/defer.py", line 1661, in _inlineCallbacks
    result = current_context.run(gen.send, result)
StopIteration: 0

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/lib/python3.9/site-packages/twisted/internet/defer.py", line 1661, in _inlineCallbacks
    result = current_context.run(gen.send, result)
StopIteration: {'ed25519:a_iiuD': FetchKeyResult(verify_key=<nacl.signing.VerifyKey object at 0x7fc8a5af6d90>, valid_until_ts=1644443665400)}

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/lib/python3.9/site-packages/synapse/federation/transport/server/federation.py", line 101, in on_PUT
    device_list_updates = [
  File "/usr/lib/python3.9/site-packages/synapse/federation/transport/server/federation.py", line 104, in <listcomp>
    if edu.edu_type in DEVICE_UPDATE_EDUS
AttributeError: 'dict' object has no attribute 'edu_type'

Die Folge, Nachrichten mit diesem Attribute kommen nicht an, weil es einen GEHEIMEN! Defaulteintrag zu einem nicht standardmäßig konfigurierten Logger gibt! Ja, richtig gelesen: Weil die Nachrichten geloggt werden sollen, kommen Sie nicht an, weil das Pythonscript vorher crasht.

Die Lösung für das Problem

Die Lösung ist sehr einfach, was man auch in diesem Commit nachlesen kann:

Öffnet die Datei log_config.yaml und ändert Sie so:

loggers:
       synapse:
            level: ERROR
            handlers: file

       synapse.8631_debug:
            level: ERROR

Danach Synapse neustarten und das war es schon. Wenn Ihr betroffen ward und kein scheues Rehlein, sondern ein Matrix Hengst seid, bricht dann leider ein wahrer Sturm über Euren Server ein, weil alle anderen Server Euch gern die verpassten Nachrichten zustellen wollen. Kurzfristige Loadwarnungen sind zu tolerieren 😉