Functional programming with Elixir
Big Brother
Listing 5 shows the proxy configuration (Figure 1). It resides in the mix.exs
file in the htdist
project directory. In contrast to the HTTP server, the proxy does without Plug
and uses the Httpoison module (line 18) to forward HTTP requests to the web server on the local network. Additionally, the configuration starting in line 11 has an application callback, which runs application()
when the application is executed. The mod: { Htdist.Supervisor, []}
(line 12) statement in the return value of the function in turn calls start()
(Listing 6, line 5) from the Htdist.Supervisor module.
Listing 5
htdist/mix.exs (Proxy Configuration)
Listing 6
htdist/lib/httpd.supervisor.ex (Supervisor)
Elixir achieves fault tolerance and scalability through its process model. Lightweight Elixir threads handle the work. If an error occurs in a thread, Elixir terminates the thread and not the application. The error message is typically handled by a supervisor that runs within the application process. The supervisor is also responsible for restarting the thread. Listing 6 shows the code for the supervisor from the Htdist.Supervisor module, which is enabled in line 12 of Listing 5 when the system starts.
The Application
macro (line 2) promotes the module to an application; Supervisor
(line 3) integrates additional functionality. The start_link()
function in line 6 wakes up the supervisor. The first parameter in the call hands over the supervisor's name, which is stored in the __MODULE__
variable.
Once activated, the supervisor in turn calls the init()
function (line 9). From within its function body, supervise()
in line 10 starts the proxy (Listing 7), which runs in its own thread and is monitored by the supervisor.
Listing 7
htdist/lib/htdist.ex (Proxy Module)
If the proxy were to terminate with an error, the supervisor would simply dust it down, and get it running again "one for one."
Controls
When Elixir loads a module, the supervisor by default calls the start_link()
function (Listing 7, line 2). In the next line, the compile()
function creates a router by calling the Cowboy_router module. It stores a router in the dispatch
variable. In this case, it fields HTTP requests much like the plugs :match
and :dispatch
from Listing 4.
The router picks up its configuration from the list at the end of line 3. It uses the configuration to evaluate requests for various IP addresses and port numbers. The pattern :_
in the first tuple matches any conceivable IP address and port number, and the /[...]
pattern matches any URL. Finally, line 3 calls the Distr module. In line 4 of Listing 7, start_http()
fires up the web server. Thanks to the dispatch
variable assigned at the start, the router ends up in the parameter list along with its IP address and port number.
The Distr module (Listing 8) becomes active when called by line 3 in Listing 7. It creates the HTTP response in the style of a load balancer. The module's init()
and terminate()
functions are mandatory, but the handle()
callback function takes care of the HTTP requests (lines 10-18). For each HTTP request that arrives, the function stores the request object in the req
variable and the request processing status in state
.
Listing 8
htdist/lib/distr.ex (Load Balancer)
Line 11 copies the requested URL to the request object and stores the value in the url
variable. Line 12 forwards the HTTP request to a local HTTP server. To do so, it calls request()
from the Httpoison module; the proxy restricts itself to getting requests (:get
).
The next function called, next_url()
, resides in lines 20-23. It translates the URL of the HTTP request to an address on the local network. In line 21, the parse()
function from the standard URI module breaks down the incoming URL into its address components. The next line reproduces the URL based on the address components, but without the IP component.
The next_host()
function (lines 25-29) then replaces the IP component with the IP address of a HTTP server on the local network; the server is chosen randomly. This choice is handled by a pseudo-random-number generator, which is seeded in line 26. In the following line, the next
variable accepts the header of the shuffled list of target addresses. Line 28 then returns the result, which is then evaluated in lines 13 and 14. These lines push the response to the HTTP request through a case distinguisher with two possible results.
If successful, the pattern matches the first case. In response to this, line 13 copies the status code, the body, and all the other metadata from the HTTP response to the three variables code
, body
, and headers
(line 12). In case of an error, the code in line 14 assigns constant values to the three variables – again, the _
operator plays a prominent role.
Based on the three variables, the call to the reply()
function in line 16 finally creates an HTTP response and stores the response in the reply
variable, which returns the next line along with the :ok
literal and the state
to the web server as a response.
Launch the proxy application by again calling a shell and loading the dependencies; then, build the application before typing the iex
command:
mix deps.get mix deps.compile sudo iex -S mix
To complete the application illustrated in Figure 1, you then need to open another shell and initialize an additional HTTP server with the new IP address 127.0.0.4. To do so, enter the following:
cd httpd sudo iex -S mix Plug.Adapters.Cowboy.http Httpd, [], \ ip: {127, 0, 0, 4}, port: 80
Figure 5 shows the load balancer on the right in a practical application on Ubuntu 14.04. When http://127.0.0.2/info is requested using the Firefox browser, the application responds with the reply from Figure 4. However, the value of the host
field varies randomly between the IP addresses of the two web servers.
Conclusions
Elixir can conveniently use the Erlang ecosystem. At the same time, Elixir dumps the muddle of academic concepts that typically make functional languages inaccessible to mere mortals. This means that programmers can develop easily maintainable and fault-tolerant applications quickly. Moreover, macros help extend Elixir's language set and simplify the program code. This is pretty much what the future of programming might come to be.
Infos
- Elixir: http://elixir-lang.org
- Erlang: http://www.erlang.org
- Haskell: http://learnyouahaskell.com/syntax-in-functions#pattern-matching
- Cowboy: http://ninenines.eu
- Plug: https://github.com/elixir-lang/plug
- Connect: https://github.com/senchalabs/connect#readme
- Data structures: http://elixir-lang.org/getting-started/meta/quote-and-unquote.html
- Hex.pm: http://hex.pm
« Previous 1 2
Buy this article as PDF
(incl. VAT)
Buy Linux Magazine
Subscribe to our Linux Newsletters
Find Linux and Open Source Jobs
Subscribe to our ADMIN Newsletters
Support Our Work
Linux Magazine content is made possible with support from readers like you. Please consider contributing when you’ve found an article to be beneficial.
News
-
Gnome 48 Debuts New Audio Player
To date, the audio player found within the Gnome desktop has been meh at best, but with the upcoming release that all changes.
-
Plasma 6.3 Ready for Public Beta Testing
Plasma 6.3 will ship with KDE Gear 24.12.1 and KDE Frameworks 6.10, along with some new and exciting features.
-
Budgie 10.10 Scheduled for Q1 2025 with a Surprising Desktop Update
If Budgie is your desktop environment of choice, 2025 is going to be a great year for you.
-
Firefox 134 Offers Improvements for Linux Version
Fans of Linux and Firefox rejoice, as there's a new version available that includes some handy updates.
-
Serpent OS Arrives with a New Alpha Release
After months of silence, Ikey Doherty has released a new alpha for his Serpent OS.
-
HashiCorp Cofounder Unveils Ghostty, a Linux Terminal App
Ghostty is a new Linux terminal app that's fast, feature-rich, and offers a platform-native GUI while remaining cross-platform.
-
Fedora Asahi Remix 41 Available for Apple Silicon
If you have an Apple Silicon Mac and you're hoping to install Fedora, you're in luck because the latest release supports the M1 and M2 chips.
-
Systemd Fixes Bug While Facing New Challenger in GNU Shepherd
The systemd developers have fixed a really nasty bug amid the release of the new GNU Shepherd init system.
-
AlmaLinux 10.0 Beta Released
The AlmaLinux OS Foundation has announced the availability of AlmaLinux 10.0 Beta ("Purple Lion") for all supported devices with significant changes.
-
Gnome 47.2 Now Available
Gnome 47.2 is now available for general use but don't expect much in the way of newness, as this is all about improvements and bug fixes.