Open Source im professionellen Einsatz
Linux-Magazin 09/2015
1012

Code-Veredelung

Listing 4 zeigt den Code der Datei »lib/httpd.ex« . Darin antwortet das Modul Httpd auf HTTP-Anfragen und spannt dabei das Elixir-Modul Plug ein. Das bearbeitet HTTP-Anfragen in einer Pipeline, ähnlich wie das Node.js-Middleware-Framework Connect [6].

Listing 4

httpd/lib/httpd.ex (Httpd-Modul)

01 defmodule Httpd do
02   use Plug.Router
03   use Plug.Builder
04
05   plug Plug.Static, at: "/", from: "/home/pa"
06   plug :match
07   plug :dispatch
08
09   get "/info" do
10     send_resp(conn, 200, inspect(conn))
11   end
12
13   match _ do
14     send_resp(conn, 404, "Not found!")
15   end
16 end

Das Plug-Framework übernimmt zunächst ein Anfrage-Objekt von einem Webserver und reicht es an eine Reihe von Filterfunktionen weiter, an die so genannten Plugs. Diese werten das Objekt aus, modifizieren es und delegieren es an das nachfolgende Plug. Alternativ veranlassen die Plugs das Framework über den Aufruf der Funktion »send_resp()« (Zeilen 10 und 14), die Pipeline zu beenden. Aus den Aufrufparametern der Funktion konstruieren sie dann eine HTTP-Antwort und schicken diese an den Webserver zurück (Abbildung 3).

Abbildung 3: Die Funktion send_resp() beendet die Pipeline und schickt eine HTTP-Antwort an den Webserver.

Zunächst bindet Listing 4 aber die Makros »Plug.Router« und »Plug.Builder« ein. Die Funktion »plug()« (Zeilen 5 bis 7) registriert die Plugs und hält sie in einem Fifo (First in, first out) vor. Wie weiter oben beschrieben, arbeitet das Programm den Fifo ab, sobald ein Anfrage-Objekt eintrifft.

Das Plug »Static« in Zeile 5 bildet eine URL auf das Verzeichnissystem des Servers ab. Dank der »at:« -Angabe liefert die URL »http://127.0.0.3/info.html« die Datei »/home/pa/info.html« an den Client zurück. Passt auf die URL keine Datei, kümmert sich das folgende Plug um die HTTP-Anfrage. Dabei arbeiten »:match« und »:dispatch« Hand in Hand. Während »:match« per Musterabgleich nach passenden HTTP-Anfragen sucht und Treffer an »:dispatch« weiterleitet, kümmert sich das zweite um die HTTP-Antwort.

Die Codeblöcke der Zeilen 9 bis 11 sowie 13 bis 15 zeigen dabei keinen regulären Elixir-Code. Vielmehr handelt es sich um Code-Erweiterungen der Plug-Erfinder [7]. Das darin auftretende Makro »Plug-Router« wandelt diese Codeblöcke beim Erstellen des Syntaxbaums in gültige Baumbestandteile um. Theoretisch ließe sich der Codeblock auch als Elixir-Ausdruck umsetzen:

{method: "get", url: "/info", _} -> Usend_resp(conn, 200, inspect(conn))

Listing 4 geht jedoch einen anderen Weg. Die Zeilen 9 bis 11 geben für die URL »/info« dank der Funktion »inspect()« eine formatierte Version des Anfrage-Objekts im Körper der HTTP-Antwort aus. Als Antwortcode schreibt die Funktion »200« in den Kopf der Antwort. Für alle noch nicht beantworteten Anfragen gibt der Ausdruck ab Zeile 13 die bekannte »404« -Meldung über den Webserver an den Client zurück.

Vor dem Start der Anwendung wechselt der Benutzer mit »cd httpd« ins Projektverzeichnis und kompiliert die Anwendung mit Hilfe von »mix« . Der Befehl »mix deps.get« lädt zunächst die Quellcodes der benötigten Module aus Hex.pm [8], dem gemeinsamen Paketarchiv von Erlang und Elixir, dann verwandelt ein »mix deps.compile« die Anwendung in eine Schar von Beam-Dateien. Sie landen im Projektverzeichnis unterhalb des Ordners »_build« .

Der Befehl »sudo iex -S mix« läutet erneut eine interaktive Sitzung ein. Der Funktionsaufruf

Plug.Adapters.Cowboy.http Httpd, [], ip:  {127, 0, 0, 3}, port: 80

startet eine Instanz des Webservers aus dem Cowboy-Framework. Der ist dann über die IP-Adresse »127.0.0.3« und Port 80 erreichbar und lädt das Modul aus Listing 4, das auf HTTP-Anfragen wartet. Abbildung 4 zeigt das formatierte Anfrage-Objekt als Antwort auf die Anfrage-URL »http://127.0.0.3/info« in der Browseransicht von Firefox.

Abbildung 4: Das Anfrage-Objekt Plug.Conn ist vom Datentyp Struct. Der Wert speichert alle typischen Parameter einer HTTP-Anfrage.

Großer Bruder

Listing 5 zeigt die Konfiguration des Proxys (Abbildung 1). Sie steckt in der Datei »mix.exs« im Projektverzeichnis »htdist« . Im Gegensatz zum HTTP-Server verzichtet der Proxy auf Plug und verwendet das Modul Httpoison (Zeile 18), um HTTP-Anfragen an die Webserver im lokalen Netzwerk weiterzureichen. Zusätzlich verfügt die Konfiguration ab Zeile 11 über einen Application-Callback, der »application()« beim Start der Anwendung ausführt. Die Angabe »mod: { Htdist.Supervisor, []}« (Zeile 12) im Rückgabewert der Funktion ruft ihrerseits »start()« (Listing 6, Zeile 5) aus dem Modul Htdist.Supervisor auf.

Listing 5

htdist/mix.exs (Proxy-Konfiguration)

01 defmodule Htdist.Mixfile do
02   use Mix.Project
03
04   def project do
05     [app: :htdist,
06      version: "0.0.1",
07      elixir: "~> 1.0",
08      deps: deps]
09   end
10
11   def application do
12     [ mod: { Htdist.Supervisor, []},
13       applications: [:cowboy, :httpoison]]
14   end
15
16   defp deps do
17     [{:cowboy, "~> 1.0.0"},
18      {:httpoison, "~> 0.7"}]
19   end
20 end

Fehlertoleranz und Skalierbarkeit erreicht Elixir durch sein Prozessmodell. Die leichtgewichtigen Elixir-Threads übernehmen die Arbeit. Tritt im Thread ein Fehler auf, beendet Elixir den Thread, nicht aber die Anwendung. Die Fehlermeldung behandelt gewöhnlich ein Supervisor, der im Prozess der Anwendung läuft. Er ist auch für den Neustart des Thread verantwortlich. Listing 6 zeigt den Code des Supervisors aus dem Modul Htdist.Supervisor, den die erwähnte Zeile 12 aus Listing 5 beim Systemstart aktiviert.

Listing 6

htdist/lib/httpd.supervisor.ex (Supervisor)

01 defmodule Htdist.Supervisor do
02   use Application
03   use Supervisor
04
05   def start(_type, _args) do
06     Supervisor.start_link(__MODULE__, :ok)
07   end
08
09   def init(:ok) do
10     supervise([worker(Htdist, [])], strategy: :one_for_one)
11   end
12
13 end

Das Makro »Application« (Zeile 2) erhebt das Modul zu einer Anwendung, »Supervisor« (Zeile 3) bindet zusätzliche Funktionalität ein. Die Funktion »start_link()« in Zeile 6 erweckt einen Supervisor zum Leben. Dabei übergibt der Aufruf im ersten Parameter den Namen des Supervisors, der in der Variablen »__MODULE__« steckt.

Einmal aktiviert, ruft der Supervisor seinerseits die Funktion »init()« (Zeile 9) auf. Aus ihrem Funktionskörper heraus startet »supervise()« in Zeile 10 den Proxy aus Listing 7, der in einem eigenen Thread läuft und den der Supervisor überwacht. Bricht der Proxy mit einem Fehler ab, würde der Supervisor ihn gemäß der Strategie "One for one" erneut aufs Gleis setzen.

Diesen Artikel als PDF kaufen

Express-Kauf als PDF

Umfang: 5 Heftseiten

Preis € 0,99
(inkl. 19% MwSt.)

Linux-Magazin kaufen

Einzelne Ausgabe
 
Abonnements
 
TABLET & SMARTPHONE APPS
Bald erhältlich
Get it on Google Play

Deutschland

Ähnliche Artikel

  • Elixir in Version 1.3 mit Kalendermodul

    Änderungen am Buildtool und am Test-Framework stechen als Neuerungen an Version 1.3 von Elixir ebenso hervor wie jene an der Sprache selbst. Neu ist auch ein Kalendermodul.

  • Phoenix 1.0: Web-Framework auf Elixir-Basis

    Anderthalb Jahre haben Entwickler an einem Web-Framework gearbeitet, das auf der funktionalen Programmiersprache Elixir basiert. Nun ist Phoenix in Version 1.0 zu haben.

  • Ruby on Rails

    Läuft alles nach Plan, setzen die Ruby-on-Rails-Macher Ende April 2017 die neue Version 5.1 aufs Gleis. Die liebt Javascript und hat unter anderem den flinken Javascript-Paketmanager Yarn an Bord. Zudem kann sie dank eigener Javascript-Bibliothek erstmals auf Jquery als Default-Option verzichten.

  • Crystal

    Das Open-Source-Projekt Crystal will das Beste zweier Welten vereinen: Die Einfachheit einer weitgehend zu Ruby ähnlichen Sprachsyntax mit der Geschwindigkeit und den Möglichkeiten der LLVM-Plattform.

  • Docker 1.0

    Dieser Workshop zeigt am Beispiel des Cloudstack Owncloud, wie stark die Entwickler das Integrieren etablierter Linux-Technologien wie LXC und Cgroups in Docker 1.0 abstrahiert und vereinfacht haben und wie Admins komplexe Szenarien in Containerumgebungen zähmen.

comments powered by Disqus

Ausgabe 07/2017

Digitale Ausgabe: Preis € 6,40
(inkl. 19% MwSt.)

Artikelserien und interessante Workshops aus dem Magazin können Sie hier als Bundle erwerben.