Pinned Post

NodePulse: so your Lightning node speaks up before it gets expensive

Bild
  A Lightning node is an odd kind of device. It sits on a shelf somewhere, a Raspberry Pi with an SSD, and as long as everything works you don’t look at it for weeks. That is exactly the problem. When LND hangs, the SSD fills up or a peer has been offline for days, nobody tells you. You only notice when a payment fails. Or worse: when an HTLC is about to expire and nobody reacts. RaspiBlitz comes with a lot, but not with alerting that actively nudges me. The ready-made solutions I looked at were either too big (Prometheus, Grafana and Alertmanager on a Pi that is supposed to run a Bitcoin node) or they ran as a service somewhere else, with access to my node data. I didn’t want either. So I built NodePulse. A small program that runs directly on the node, checks every minute whether everything is fine, and sends me a Telegram message when it isn’t. And another one once the problem is gone. On top of that there is a dashboard in the browser. In this article I explain what NodePulse...

Erlang Code Loading

Um geänderte Module neu zu laden, kann man entweder die VM neu starten oder aber nur die Module
neu laden, die sich geändert haben.

Die erste Methode kennt bestimmt jeder, aber die zweite vielleicht nicht. Ich benutze diese zweite Methode in meinem Continuous Integration Prozess, indem ein Prozess die geänderten Sourcen aus SCM lädt, baut und dann die Nachricht an den sogenannten code_reloader schickt, damit dieser die geänderten Module neu laden soll.

Wie funktioniert das im Detail?

Zunächst einmal ermitteln wir alle Module, die z.Z. geladen sind.

code:all_loaded()

Diese Funktion gibt uns eine voll qualifizeirte Liste aller geladenen Module zurück. Wir könnten nun über die Liste iterieren und einfach alle Module neu laden, aber das wäre langweilig.

Deswegen überprüfen wir zunächst, ob es sich bei der Datei um ein beam File handelt. Das ist für unsere späteren Schritte wichtig.
Um das zu überprüfen schaun wir nach, ob die zu überprüfende Datei Metadaten besitzt.

file:read_file_info(File)

Wir werten diese Daten nicht aus, es reicht uns das diese vorhanden sind.
Metadaten können sein, siehe : file:read_file_info


Da das Modul code nur Dateien liest, die die Endung beam haben ( code:load_file) müssen wir noch prüfen, ob die Datei diese Endung auch besitzt.


filename:extension(File)


Diese Überprüfungen reichen aber moch nicht aus um eine Liste zu erzeugen, die nur die geänderten Module enthält. Deshalb überrpüfen wir nun, ob es Module gibt, die ein jüngeres Compile Datum haben.


Man kann zur Laufzeit bestimmte Metadaten eines Modules mittels module_info() abfragen. So z.B. die funktionen die export werden, eigene Attribute wie die vsn, author und viele mehr.


Wir nutzen das Compile Datum, das ebenfalls in den Metadaten hinterlegt wurde, um zu prüfen ob ein geladenes Module älter ist als das was in dem ebin Verzeichnis liegt.


1. Auslesen des Compile Datums des geladenen Modules

proplists:get_value(time, Module:module_info(compile))


2. Auslesen des Compile Datums des Modules, das im ebin Verzeichnis liegt

{ok,{_,[{_,I}]}} = beam_lib:chunks(File,[compile_info]),
proplists:get_value(time,I).



Dazu nutzen wir das Modul beam_lib, das uns den Zugriff auf die Beam Files ermöglicht. Mit der Funktion chunks können wir die Compile Informationen ermitteln und dann die Compile Zeit auslesen.

Nun haben wir die Liste der Module, die sich geändert haben und können diese nun neu laden. Bevor wir den neuen Code laden, entladen wir den alten Code mittels code:purge und laden dann den neuen Code mittels code:load_file

Alles zusammen ergibt dann :

[load_module(Module) || {Module, File} <- code:all_loaded(), is_beamfile(File), is_old(Module,File)]

Lade das Module aus der Liste aller geladenen Module, die den Filtern is_beamfile und is_old genügen. 

Vieleicht wird der eine oder andere fragen wollen, was denn mit neuen Modulen passiert. Werden diese auch neu geladen?
Diese werden nicht durch diesen Mechanismus geladen, sondern das wird durch die Laufzeit erledigt. Wenn ein Modul namentlich angesprochen wird, so wird geprüft, ob es dieses Modul schon im Speicher gibt, ansonsten wird versucht das Modul zu laden.

Kommentare

Beliebte Posts aus diesem Blog

Splitting an ML model and a web app across two BEAM nodes — the technical blueprint

Jido in Practice: Agents in Elixir as Composable Actions

A Foundation Model in the BEAM: On-Chain Anomalies with Google TimesFM in Elixir