Modern C++ programming: Coroutines with Boost


We’re rewriting our network stack in Icinga 2.11 in order to to eliminate bugs with timeouts, connection problems, improve the overall performance. Last but not least, we want to use modern library code instead of many thousands of lines of custom written code. More details can be found in this GitHub issue.

From a developer’s point of view, we’ve evaluated different libraries and frameworks before deciding on a possible solution. Alex created several PoCs and already did a deep-dive into several Boost libraries and modern application programming. This really is a challenge for me, keeping up with the new standards and possibilities. Always learning, always improving, so I had a read on the weekend in “Boost C++ Application Development Cookbook – Second Edition“.

One of things which are quite resource consuming in Icinga 2 Core is multi threading with locks, waits and context switching. The more threads you spawn and manage, the more work needs to be done in the Kernel, especially on (embedded) hardware with a single CPU core. Jean already shared insights how Go solves this with Goroutines, now I am looking into Coroutines in C++.


Coroutine – what’s that?

Typically, a function in a thread runs, waits for locks, and later returns, freeing the locked resource. What if such a function could be suspended at certain points, and continue once there’s resources available again? The benefit would also be that wait times for locks are reduced.

Boost Coroutine as library provides this functionality. Whenever a function is suspended, its frame is put onto the stack. At a later point, it is then resumed. In the background, the Kernel is not needed for context switching as only stack pointers are stored. This is done with Boost’s Context library which uses hardware registers, and is not portable. Some architectures don’t support it yet (like Sparc).

Boost.Context is a foundational library that provides a sort of cooperative multitasking on a single thread. By providing an abstraction of the current execution state in the current thread, including the stack (with local variables) and stack pointer, all registers and CPU flags, and the instruction pointer, a execution context represents a specific point in the application’s execution path. This is useful for building higher-level abstractions, like coroutinescooperative threads (userland threads) or an equivalent to C# keyword yield in C++.

callcc()/continuation provides the means to suspend the current execution path and to transfer execution control, thereby permitting another context to run on the current thread. This state full transfer mechanism enables a context to suspend execution from within nested functions and, later, to resume from where it was suspended. While the execution path represented by a continuation only runs on a single thread, it can be migrated to another thread at any given time.

context switch between threads requires system calls (involving the OS kernel), which can cost more than thousand CPU cycles on x86 CPUs. By contrast, transferring control vias callcc()/continuation requires only few CPU cycles because it does not involve system calls as it is done within a single thread.

TL;DR – in the way we write our code, we can suspend function calls and free resources for other functions requiring it, without typical thread context switches enforced by the Kernel. A more deep-dive into Coroutines, await and concurrency can be found in this presentation and this blog post.


A simple Example

$ vim coroutine.cpp

#include <boost/coroutine/all.hpp>
#include <iostream>

using namespace boost::coroutines;

void coro(coroutine::push_type &yield)
        std::cout << "[coro]: Helloooooooooo" << std::endl;
        /* Suspend here, wait for resume. */
        std::cout << "[coro]: Just awesome, this coroutine " << std::endl;

int main()
        coroutine::pull_type resume{coro};
        /* coro is called once, and returns here. */

        std::cout << "[main]: ....... " << std::endl; //flush here

        /* Now resume the coro. */

        std::cout << "[main]: here at NETWAYS! :)" << std::endl;


Build it

On macOS, you can install Boost like this, Linux and Windows require some more effort listed in the Icinga development docs). You’ll also need CMake and g++/clang as build tool.

brew install ccache boost cmake 

Add the following CMakeLists.txt file into the same directory:

$ vim CMakeLists.txt

cmake_minimum_required(VERSION 2.8.8)
set(BOOST_MIN_VERSION "1.66.0")

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")

find_package(Boost ${BOOST_MIN_VERSION} COMPONENTS context coroutine date_time thread system program_options regex REQUIRED)

# Boost.Coroutine2 (the successor of Boost.Coroutine)
# (1) doesn't even exist in old Boost versions and
# (2) isn't supported by ASIO, yet.


set(base_DEPS ${CMAKE_DL_LIBS} ${Boost_LIBRARIES})



target_link_libraries(coroutine ${base_DEPS})

        coroutine PROPERTIES
        FOLDER Bin
        OUTPUT_NAME boost-coroutine

Next, run CMake to check for the requirements and invoke make to build the project afters.

cmake .


Run and understand the program

$ ./boost-coroutine
[coro]: Helloooooooooo
[main]: .......
[coro]: Just awesome, this coroutine
[main]: here at NETWAYS! :)

Now, what exactly happened here? The Boost coroutine library allows us to specify the “push_type” where this functions should be suspended, after reaching this point, a subsequent call to “yield()” is required to resume this function.

void coro(coroutine::push_type &yield)

Up until “yield()”, the function logs the first line to stdout.

The first call happens inside the “main()” function, by specifying the pull_type and directly calling the function as coroutine. The pull_type called “resume()” (free form naming!) must then be explicitly invoked in order to resume the coroutine.

coroutine::pull_type resume{coro};

After the first line is logged from the coroutine, it stops before “yield()”. The main function logs the second line.

[coro]: Helloooooooooo
[main]: .......

Now comes the fun part – let’s resume the coroutine. It doesn’t start again, but the function’s progress is stored as stack pointer, targeting “yield()”. Exactly this resume function is called with “resume()”.

        /* Now resume the coro. */

That being said, there’s more to log inside the coroutine.

[coro]: Just awesome, this coroutine

After that, it reaches the end and returns to the main function. That one logs the last line and terminates.

[main]: here at NETWAYS! :)

Without a coroutine, such synchronisation between functions and threads would need waits, condition variables and lock guards.


Icinga and Coroutines

With Boost ASIO, the spawn() method wraps coroutines on a higher level and hides the strand required. This is used in the current code and binds a function into its scope. We’re using lambda functions available with C++11 in most locations.

The following example implements the server side of our API waiting for new connections. An endless loop listens for incoming connections with “server->async_accept()”.

Then comes the tricky part:

  • 2.9 and before spawned a thread for each connection. Lots of threads, context switches and memory leaks with stalled connections.
  • 2.10 implemented a thread pool, managing the resources. Handling the client including asynchronous TLS handshakes are slower, and still many context switches ahead between multiple connections until everything stalls.
  • 2.11 spawns a coroutine which handles the client connection. The yield_context is required to suspend/resume the function inside.


void ApiListener::ListenerCoroutineProc(boost::asio::yield_context yc, const std::shared_ptr& server, const std::shared_ptr& sslContext)
	namespace asio = boost::asio;

	auto& io (server->get_io_service());

	for (;;) {
		try {
			auto sslConn (std::make_shared(io, *sslContext));

			server->async_accept(sslConn->lowest_layer(), yc);

			asio::spawn(io, [this, sslConn](asio::yield_context yc) { NewClientHandler(yc, sslConn, String(), RoleServer); });
		} catch (const std::exception& ex) {
			Log(LogCritical, "ApiListener")
				<< "Cannot accept new connection: " << DiagnosticInformation(ex, false);

The client handling is done in “NewClientHandlerInternal()” which follows this flow:

  • Asynchronous TLS handshake using the yield context (Boost does context switches for us), Boost ASIO internally suspends functions.
    • TLS Shutdown if needed (again, yield_context handled by Boost ASIO)
  • JSON-RPC client
    • Send hello message (and use the context for coroutines)

And again, this is the IOBoundWork done here. For the more CPU hungry tasks, we’re using a different CpuBoundWork pool which again spawns another coroutine. For JSON-RPC clients this mainly affects syncing runtime objects, config files and the replay logs.

Generally speaking, we’ve replaced our custom thread pool and message queues for IO handling with the power of Boost ASIO, Coroutines and Context thus far.


What’s next?

After finalizing the implementation, testing and benchmarks are on the schedule – snapshot packages are already available for you at Coroutines will certainly help embedded devices with low CPU power to run even faster with many network connections.

Boost ASIO is not yet compatible with Coroutine2. Once it is, the next shift in modernizing our code is planned. Up until then, there are more Boost features available with the move from 1.53 to 1.66. Our developers are hard at work with implementing bug fixes, features and learning all the good things.

There’s many cool things under the hood with Icinga 2 Core. If you want to learn more and become a future maintainer, join our adventure! 🙂

Michael Friedrich
Michael Friedrich
Senior Developer

Michael ist seit vielen Jahren Icinga-Entwickler und hat sich Ende 2012 in das Abenteuer NETWAYS gewagt. Ein Umzug von Wien nach Nürnberg mit der Vorliebe, österreichische Köstlichkeiten zu importieren - so mancher Kollege verzweifelt an den süchtig machenden Dragee-Keksi und der Linzer Torte. Oder schlicht am österreichischen Dialekt der gerne mit Thomas im Büro intensiviert wird ("Jo eh."). Wenn sich Michael mal nicht in der Community helfend meldet, arbeitet er am nächsten LEGO-Projekt oder geniesst...

DEV Retreat 2018 Recap

We had a lovely time somewhere in the “Franconian Alps”, away from daily development business. Our dev retreat always includes one day of “looking back, looking forward”, the second day is reserved for fun stuff.
After a relaxed breakfast on Friday, Marius invited us into the icebreaker game. Rock-Paper-Scissors combined with catching the other team on win, really a challenge and discussions on failure afterwards. Before diving into a strategic outlook with Icinga and NETWAYS development, Flo made a shout-out for the first round of beer pong. Another group was like “hey, what’s cards against humanity with monitoring?” and just started playing, that was pure fun 🙂
Later on, we did a full retrospective of the past year in our development team. Everyone shared their current mood, with then collecting three important topics (good or bad) from the past year. This entire timeline with many milestones was put in contrast with everyone’s mood over time. Reflecting the not-so-good tasks towards the “we really love this project and technology” we created our own team “graph”.
Having shared this many feelings and milestones, we made it into another round – direct feedback on everyone’s important points, be it good or bad. We’ve then built a topic cloud from these and voted topics we would like to discuss and define solutions. The two of them were selected and we started to discuss, help each other, criticise specific points and agree on a solution together. Pure energy, and not even the BBQ being ready could have stopped us. Knowledge transfer, trainee practice, more direct feedback, interesting technologies and new projects coming up …
After all we enjoyed a lovely evening and night sitting by the campfire, playing another round of beer pong, chatting and enjoying life.
The next day our plan was to escape a room. 60 minutes, lots of puzzles and hints, to finally solve everything. It is hard to describe as everyone finds his/her role pushing the others to the next level and puzzle. And there’s discussion and “anger” afterwards that you’ve lost 20 minutes on such a stupid question … but you failed together, and that’s a good feeling even 🙂
Next to getting to know colleagues and new trainees better, my personal highlights this year are these two quotes:

During our debugging sessions, I never had that feeling that I am treated as a “dumb” trainee. My ideas and knowledge are taken into account, and I really like this in our team.

Your mission as Senior Developer or experienced developer is to share your knowledge and experience with your colleagues. Help them improve and learn from you, with the most detailed feedback you can give.

And on we go, we have to develop projects like Icinga DB, Reporting, NoMa, Mobile, support daily business with Icinga 2, Icinga Web 2, Icinga Exchange, Request Tracker, Pretix, Discourse, GitLab, Jenkins and so much more filling the timeline for next year’s dev retreat already 🙂

Michael Friedrich
Michael Friedrich
Senior Developer

Michael ist seit vielen Jahren Icinga-Entwickler und hat sich Ende 2012 in das Abenteuer NETWAYS gewagt. Ein Umzug von Wien nach Nürnberg mit der Vorliebe, österreichische Köstlichkeiten zu importieren - so mancher Kollege verzweifelt an den süchtig machenden Dragee-Keksi und der Linzer Torte. Oder schlicht am österreichischen Dialekt der gerne mit Thomas im Büro intensiviert wird ("Jo eh."). Wenn sich Michael mal nicht in der Community helfend meldet, arbeitet er am nächsten LEGO-Projekt oder geniesst...

How css-tricks improved my work life

My relationship with CSS is some kind of a love-hate one and I think that is a sentiment a lot of web-devs share with me.
My biggest issue with it is, that it is really counterintuitive and most of the time it feels a bit like solving puzzles to make things align the way you want it to.

and oftentimes it feels a lot like

Properties that mean the same thing being worded inconsistently – I’m looking at you…

vertical-align: middle;
text-align: center;

And there is also some questionable naming with ‘grey’ (#808080) being darker than ‘darkgrey’ (#a9a9a9)…
In general there are too many quirks you need to just know. Unless you work with it every day, you need to google every second line in order to write your stylesheets.
There you can find all sorts of guidelines, help, blogposts with a nice mix of bad-practices and outdated information.
What helped me a lot is the website css-tricks.
(mehr …)

A peek into GitLab 11, the Web IDE and Auto DevOps with Kubernetes

GitLab 11 was just released last week and introduces a bunch of new features. I’ve picked the most exciting ones for a short peek as our hosted production environment was already upgraded by Stefan 🙂


You can already add and edit files directly in your browser. Dirk mentioned this in his blog post, it motivates open source contributors to enhance the documentation. For larger changes we are used to fire up an IDE like Visual Studio, JetBrains Goland, PHPStorm, Atom, Eclipse, etc.
Sometimes you don’t need a full blown IDE, or you don’t have access to on your mobile device. It would be nice to have immediate results from build, compile and test stages, best in an isolated (container) environment.
The newly introduced GitLab Web IDE attempts to become a new player in the field. On the right you can already see the current pipeline job status from the latest commit. Once we’ve edited the file, we can commit (and push at once) and the CI will trigger a new job run. Just awesome!

In its current implementation, the IDE is accessible from files view only, but the roadmap proves that there’s more to come on project creation. Just type t in the main project view and search for a specific file. Then pick Web IDE from the upper left bullets and rock on. There is syntax highlighting and code auto-completion included ❤️


Auto DevOps with Kubernetes

Our vision is to replace disparate DevOps toolchains with a single integrated application that is pre-configured to work by default across the complete DevOps lifecycle.

Auto DevOps enables your CI/CD workflow to advance even further with pipeline container environments built on Kubernetes. GitLab provides its own Kubernetes integration, accompanied with default templates for projects and build pipelines. This isn’t limited to build, test, deploy stages but also includes a variety of additional stages:

  • Build and Test
  • Code Quality checks
  • Static Application Security Testing (SAST), Dynamic Application Security Testing (DAST), Dependency and container scanning for vulnerabilities
  • Review Apps, deploy current state to temporary application environment in Kubernetes (optional)
  • Deploy to Kubernetes production environment (optional)
  • Monitoring for fetching deployment metrics from the Kubernetes cluster via Prometheus exporter (optional)

You can see the changes inside the menu where Operations was introduced and provides settings for environments and Kubernetes integration. This was previously found in the CI/CD section. A Kubernetes cluster can be assigned to a specific project, you can safely play and test without harming a global environment.
Nicole and Gabriel shared more insights into GitLab 11 features in their OSDC talk on “Git things done with GitLab!”. Check the archive for a live demo especially on the Auto DevOps feature, first time I fully understood its purpose 🙂

Notable Changes

In terms of roles, GitLab renamed “Master” to “Maintainer”.

GitLab also decided to release the “Squash and Merge” option into the Open source edition. This feature allows you to develop a merge request in multiple commits, and upon merge back to master, it will automatically squash the commits into a single one. Want to learn more about git squash? We’ve got you covered in our GitLab training 🙂

I really hope that GitLab will also open-source Merge request approvals in future releases. This is something which we use for code review and release managed on GitHub on a daily basis and would enhance our GitLab flow too.
Still not enough? I’d love to talk GitLab with you in our upcoming training sessions, including the best development workflows from our daily work 🙂

Michael Friedrich
Michael Friedrich
Senior Developer

Michael ist seit vielen Jahren Icinga-Entwickler und hat sich Ende 2012 in das Abenteuer NETWAYS gewagt. Ein Umzug von Wien nach Nürnberg mit der Vorliebe, österreichische Köstlichkeiten zu importieren - so mancher Kollege verzweifelt an den süchtig machenden Dragee-Keksi und der Linzer Torte. Oder schlicht am österreichischen Dialekt der gerne mit Thomas im Büro intensiviert wird ("Jo eh."). Wenn sich Michael mal nicht in der Community helfend meldet, arbeitet er am nächsten LEGO-Projekt oder geniesst...

Releasing our Git and GitLab training as Open Source

Development is super fast these days, there are many tools and integrations to make it more comfortable. One of the version control systems is Git, next to well-known SVN and CVS. Git got really pushed by GitHub and most recently GitLab which provide entire collaboration suites. Nowadays you not only commit code revisions/diffs, you can also test and deployment changes immediately to see whether your code is good on defined platforms or breaks. Issue and project management is put on top and makes it very easy to collaborate.
Continuous integration (CI) allows for deeper code quality too. Add code coverage reports, unit test results, end2end tests and actually build distribution packages with tests on many platforms included. In addition to CI, continuous deployment (CD) adds the icing on the cake. Once CI tests and package builds are fine, add a new build job to your pipeline for automated deployments. This could for example push updated RPM packages for your repository and immediately install the bugfix release in production on all your client hosts with Puppet or Ansible.
You can do all of this with the ease of GitHub or your own hosted GitLab instance (try it out in NWS right now!). Don’t forget about the basics for development and devops workflows:

  • Untracked files, staging area, … what’s within the .git directory?
  • What is a “good commit“?
  • I want to create patch for an open source project – what’s a “pull request“?
  • Workflow with branches?
  • A developer asked me to “rebase your branch against master” and “squash the commits” … what’s that?

Our Git training sessions have been renewed into a two day hands-on session on Git and GitLab. Many of us are using Git on a daily basis at NETWAYS, in addition to GitLab. Knowledge which we share and improve upon. The training starts with the Git basics, diving into good commits, branching, remote repositories and even more. Day 1 also provides your own NWS hosted GitLab instance.
Starting with day 2, you’ll learn about development workflows with branches and real-life use cases. Continuing with CI/CD and generating your own Job pipeline, and exploring GitLab even further. We’ll also discuss integrations into modern development tools (Visual Studio, JetBrains, etc.) and have time to share experiences from daily work. I’ve been working with Git since the beginning of Icinga more than nine years ago.
We have open-sourced our GitLab training material. We truly believe in Open Source and want make it easier for development and contributions on your favourite OSS project, like Icinga.
You are welcome to use our training material for your own studies, especially if you are an open source developer who’s been learning to use Git, GitLab and GitHub. For offline convenience, the handouts, exercises and solutions are provided as PDF too.
Many of the mentioned practical examples and experiences are only available in our two day training sessions at NETWAYS so please consider getting a ticket. There’s also time for your own experience and ideas – the previous training sessions have shown that you can always learn something new about Git. You can see that in the Git repository and the newer Git commits, where this feedback was added to the training material ❤️
See you soon at the famous NETWAYS Kesselhaus for a deep-dive into Git and GitLab!
Please note that the training material is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International.

Michael Friedrich
Michael Friedrich
Senior Developer

Michael ist seit vielen Jahren Icinga-Entwickler und hat sich Ende 2012 in das Abenteuer NETWAYS gewagt. Ein Umzug von Wien nach Nürnberg mit der Vorliebe, österreichische Köstlichkeiten zu importieren - so mancher Kollege verzweifelt an den süchtig machenden Dragee-Keksi und der Linzer Torte. Oder schlicht am österreichischen Dialekt der gerne mit Thomas im Büro intensiviert wird ("Jo eh."). Wenn sich Michael mal nicht in der Community helfend meldet, arbeitet er am nächsten LEGO-Projekt oder geniesst...

Ansible, so einfach!

Konfigurationsmanagement in Rechenzentren ist aus der modernen “DevOps” IT nicht mehr wegzudenken. Puppet, Chef, Salt oder Ansible automatisieren Umgebungen von mittelständischen Unternehmen bis hin zu Weltkonzernen.
Wenn wir die verschiedenen Lösungen betrachten, bedienen sie sich alle einer eigenen Sprache, diese soll möglichst einfach unsere Infrastruktur abbilden. (“infrastructure as a code”)
Da nicht jeder Admin im Tagesgeschäft programmiert, kann so eine Sprache ein Hindernis werden und Arbeitsschritte vielleicht verkomplizieren.
Seit einiger Zeit beschäftige ich mit Ansible, ein Tool welches ohne vorinstallierte Clients arbeitet und eine Konfiurationsprache basierend auf YAML nutzt.
Um Ansible zu nutzen muss lediglich eine SSH Verbindung, ein Benutzer mit Rootrechten und ein Inventarfile bestehen.
Das Sprache im YAML Format ist für jeden leicht lesbar und sofort verständlich.
Ansible kann entweder lokal auf dem Arbeitsrechner oder auf einem sogenannten “Managementnode” über bereitgestellte Pakete installiert werden.
Unter “/etc/ansible/” legen wir nach der Installation zusätzlich ein Inventar an.

$ cat /etc/ansible/hosts
host01.localdomain ansible_ssh_host=
host02.localdomain ansible_ssh_host=</pre lang="bash">

Wenn Ansible installiert und ein Inventarfile erstellt wurde, kann die Verbindung zum Server mit dem Modul “ping” getestet werden. Hierbei versucht Ansible den Server per SSH zu erreichen und einzuloggen.

$ ansible host01.localdomain -m ping
host01.localdomain | success >> {
"changed": false,
"ping": "pong"
}</pre lang="bash">

Alternativ kann statt dem Hostalias auch “all” gesetzt werden um alle Hosts aus dem Inventar zu prüfen.

$ ansible all -m ping</pre lang="bash">

Ansible bietet zahlreiche Module mit denen Pakete installiert, Dateien kopiert oder bearbeitet werden können. Hier findet ihr eine Übersicht aller Module
Tasks verwenden diese Module um die Arbeitsschritte in Playbooks oder Rollen auszuführen.
Beispiel eines Playbooks:

$ cat ansible_starter.yml
- hosts: all <- Führe die Tasks auf allen Hosts aus
    - name: say hello to everyone <- Name des Tasks
      debug:                      <- Name des Moduls
        msg: "Hello World"        <- Parameter des Moduls

– name: install ntp
name: ntp
state: installed
</pre lang=”yaml”>

$ ansible-playbook -s ansible_starter.yml
</pre lang="bash">
Diese Task werden der Reihenfolge nach auf dem Zielhost ausgeführt und damit haben wir schon eine kleine Automation geschaffen. Probiert's aus!

Da Ansible im Sturm mein Automationsherz erobern konnte war ich mit meinem Kollegen dieses Jahr auf dem Ansible Fest in London, einen Erfahrungsbericht der Veranstaltung findet ihr hier.

Thilo Wening
Thilo Wening
Senior Consultant

Thilo hat bei NETWAYS mit der Ausbildung zum Fachinformatiker, Schwerpunkt Systemadministration begonnen und unterstützt nun nach erfolgreich bestandener Prüfung tatkräftig die Kollegen im Consulting. In seiner Freizeit ist er athletisch in der Senkrechten unterwegs und stählt seine Muskeln beim Bouldern. Als richtiger Profi macht er das natürlich am liebsten in der Natur und geht nur noch in Ausnahmefällen in die Kletterhalle.

May I introduce the Rubocop

When you are into developing Ruby code, or even Ruby near stuff like Puppet modules, or Chef cookbooks, there is a nice tool you should have a look at.
The RuboCop can help you writing better Ruby code, it certainly did it for me.
In short words, RubyCop is a code analyzer that checks Ruby code against common style guidelines and tries to detect a lot of mistakes and errors that you might write into your code.
There are a lot of configuration options, and even an auto-correct functionality, that updates your code.

Simple usage

Either install the gem, or add it to your Gemfile:

gem 'rubocop', require: false

You can just run it without configuration, and it will look for all Ruby files in your work directory.

$ rubocop
Inspecting 19 files
lib/test/cli.rb:3:3: C: Missing top-level class documentation comment.
 class CLI
lib/test/cli.rb:36:1: C: Extra empty line detected at method body beginning.
lib/test/cli.rb:41:1: C: Extra empty line detected at block body beginning.
lib/test/cli.rb:45:4: C: Final newline missing.
bin/test:12:1: C: Missing space after #.
#api.login('username', 'Passw0rd') unless api.logged_in?
bin/test:15:3: C: Missing space after #.
 #puts response.code
bin/test:19:1: C: Missing space after #.
18 files inspected, 7 offenses detected

You can add it as a rake job to your Rakefile:

require 'rubocop/rake_task'
task default: [:spec, :rubocop]

And run the test via your rake tests:

$ rake
$ rake rubocop

Configuration galore

There are a lot of options to modify the behavior and expectations of RuboCop.
Here is a short example I used with recent Puppet module.

require: rubocop-rspec
  TargetRubyVersion: 1.9
    - ./**/*.rb
    - vendor/**/*
    - .vendor/**/*
    - pkg/**/*
    - spec/fixtures/**/*
# We don't use rspec in this way
  Enabled: False
  Enabled: False
# Example length is not necessarily an indicator of code quality
  Enabled: False
  Enabled: False

Where to go next

Markus Frosch
Markus Frosch
Principal Consultant

Markus arbeitet bei NETWAYS als Principal Consultant und unterstützt Kunden bei der Implementierung von Nagios, Icinga und anderen Open Source Systems Management Tools. Neben seiner beruflichen Tätigkeit ist Markus aktiver Mitarbeiter im Debian Projekt.

Fronted-Performance optimieren in Chrome – Like a Boss

Nicht nur Frontend Entwickler kennen es: Man freut sich, dass die hollywoodreifen Animationen auf der Webseite oder im User Interface endlich funktionieren. Ein raffinierter Parallax-Effekt verleiht dem Ganzen dann noch den letzten Schliff. Das Problem: Es ruckelt und hakt an allen Enden, die Lüfter seines nagelneuen Rechners fangen an zu drehen. Was tun?
Zum Glück bieten die Chrome-Developer Tools einige hilfreiche Werkzeuge an, um die Performancefresser zu identifizieren. Diese geben nicht nur einen guten Überblick über Performance-Engpässe sondern dokumentieren außerdem die Bildwiederholrate, CPU-Auslastung und das Asset-Handling.

Wo finde ich diese Tools nun?

Wer die Chrome Developer-Tools kennt, ist möglicherweise schon mal über das Timeline Tab gestolpert. Öffnet man die Ansicht das erste Mal, ist es nicht ganz unwahrscheinlich, dass man von der hohen Informationsdichte erschlagen ist. Daher soll dieser Artikel als eine Art Entry-Point für den Einstieg sein. Denn es lohnt sich.
Ist das Timeline-Tab bereits geöffnet und die Seite wird neu geladen, werden die Performance-Daten des initialen Seitenaufrufes bis zum fertigen Rendern der Seite automatisch aufgezeichnet.
Danach kann man einzelne Aufzeichnungen starten, um z.B. die Performance einzelner Interaktionen auf der Seite untersuchen zu können. Dabei sollte beachtet werden: Je kürzer die Aufnahme und je weniger Aktionen aufgezeichnet werden, desto einfacher ist die Analyse.


Der Einstieg: Ein kurzer Überblick über die Oberfläche.
Bildschirmfoto 2016-03-30 um 13.07.21

A) Bedienelemente

Die beiden linken Symbole dienen zum Starten und Stoppen der Aufzeichnung. Alternativ kann hierfür das Tastenkürzel cmd + E / Strg + E verwendet werden. Mit den Checkboxen können zusätzliche Informationen an/abgewählt werden, die dann entsprechend mit aufgezeichnet werden.

B) Überblick

Diese Ansicht bietet eine Übersicht über den Verlauf der Seiten-Performance. Sie dient außerdem als Navigation, um den aktuellen Bereich auszuwählen.

C) Flame-Chart

Hier werden die einzelnen Ereignisse und deren Dauer als horizontale Balken visualisiert. Parallele Ereignisse werden nach unten gestapelt. Der findige Beobachter erkennt hier drei unterschiedliche gefärbte vertikale gestrichelte Linien: die blaue Line stellt den DOMContentLoaded-Event dar. Die grüne Linie markiert den ersten Paint-Event und die rote den load Event.

D) Details

Ist kein Ereignis angewählt werden hier die Statistiken für  Zeitraum aufgeführt, der in der Übersichtsansicht ausgewählt ist. Um die Anzeige auf ein Ereignis zu begrenzen, kann im Flame-Chart ein Ereignis ausgewählt werden.
In der Überblicksansicht kann man die Auswahl der Ereignisse eingrenzen in dem man die Regler verschiebt. Die Visualisierungen im Flame-Chart und dem Detailbereich passen sich entsprechend an und beziehen sich nur auf den ausgewählten Bereich.
2016-03-30 16_25_29

Exkurs: Die typische Rendering-Pipeline

In der Regel gibt es fünf verschiedene Schritte bei der Frame-Berechnung, die bei der Entwicklung zu beachten sind. Über diese Bereiche hat  der Entwickler die größte Kontrolle.


Typischerweise werden Scriptaufrufe verwendet um Werte zu ändern, die dann in Änderungen der Darstellung resultieren. Das kann z.B. die animate Funktion in jQuery sein oder das Hinzufügen von DOM-Elementen. Diese Darstellungsänderungen werden nicht ausschließlich durch Javascript ausgelöst. Es können auch CSS-Animationen, Transistions, o.ä. dafür verantwortlich sein.

Style Calculations

In diesem Prozess findet der Browser heraus, welche CSS-Regeln anhand der Style-Angaben für welche Elemente angewandt werden müssen.


Darauf folgt in der üblicherweise die Berechnung der Positionen der jeweiligen Elemente und wie viel Platz diese benötigen. Das Layout-Modell des Webs ist so konzipiert, dass gewisse Abhängigkeiten der Elemente untereinander herrschen. Verändert ein Element, welches mit float positioniert ist seine Breite, beeinflusst es die Position und Größe der umliegenden Elemente.


Im Painting-Prozess werden die Pixel der einzelnen Elemente berechnet. Es berücksichtigt Eigenschaften wie Text, Farben, Bilder, Rahmen. Die Berechnung findet auf verschiedenen Ebenen (Layers) statt.


Nachdem Painting-Prozess sind die einzelnen Komponenten (Layers) der Seite bereits berechnet. Beim Compositing werden diese Komponenten dann übereinander gelegt. Besonders entscheidend ist dies bei überlappenden Elementen.

1. JS/CSS >Style > Layout > Paint > Composite

Pasted Graphic
Wenn eine Eigenschaft eines Elements verändert wird, welche dessen Abmessungen oder Position verändert (z.B. height, width, top, left, o.ä, muss der Browser alle oder zumindest alle umliegenden Elemente neu berechnen und zusammengesetzt werden (Layout > Paint > Composite)

2. JS/CSS > Style > Paint > Composite

Pasted Graphic 1

Werden nur Paint-only Eigenschaften geändert (background-image, color, box-shadow), kann der Browser den Layout-Prozess überspringen.

3. JS/CSS > Style > Composite

Pasted Graphic 2

Wenn eine Eigenschaft verändert wird, bei denen der Layout und Painting-Prozess übersprungen werden kann, überspringt der Browser diese Schritte und springt direkt in den Compositiing-Prozess. Darunter fallen z.B. transform oder opacity.
Vor allem für performance-kritische Fälle, z.B. für Animationen oder bei Scroll-Events, bei denen die entsprechenden Funktionen in der Regel besonders oft aufgerufen werden, ist diese Variante besonders erstrebenswert.

Repaintbereiche auf der Seite visualisieren

Im DevTools Hauptmenü gibt es einen Eintrag mit der Bezeichnung More Tools nennt. Wählt man hier die Rendering Settings aus, erhält man weitere Funktionen. Ist die zusätzliche Leiste am unteren Bildschirmrand nicht sichtbar, kann man diese mit der Esc-Taste wieder erscheinen lassen.
Im Teilfenster am unteren Bildschirmrand befindet sich dann eine Check-Box mit dem Titel Enable paint flashing.


Über das DevTools Hauptmenü können weitere Tools eingeblendet werden.

Aktiviert man diese werden auf der Seite Bereiche markiert, bei denen Painting-Events auftreten. So erhält man in Echtzeit einen guten Überblick, welche Bereiche für mögliche Performance-Engpässe sorgen.
2016-03-30 22_26_11
Es gibt einen Talk von Paul Irish, der mehrere Anwendungsbeispiele veranschaulicht.

Florian Strohmaier
Florian Strohmaier
UX Designer

Mit seinen Spezialgebieten UI-Konzeption, Prototyping und Frontendentwicklung unterstützt Florian das Dev-Team bei NETWAYS. Trotz seines Design-Backgrounds fühlt er sich auch in der Technik zuhause. Gerade die Kombination aus beidem hat für ihn einen besonderen Reiz.

Working with git subtree

In case your are organising multiple git repositories and add them into one global, the most obvious choice is to use git submodule. It basically creates a pointer to a specific git commit hash in a remote repository allowing you to clone the repository into a sub directory as module.
Adding submodules is fairly easy, purging them can become cumbersome. When we were working on the Icinga Vagrant boxes one issue was to re-organize the used puppet modules into a central modules directory, as well as purge all local copies and instead use the official git repositories others provided.
Using git submodules turned out to be simple to add, but ugly to manage. Users normally forgot to initialise and update the submodules, and if the developers (me) decided to add/remove modules, it was always in sort of an incompatible check-out state. A fresh git clone –recursive always helped (hi Bernd) but in the end it wasn’t satisfying to work with as users struggled from a simple demo setup with Vagrant.
Looking for alternatives unveiled git subtree as originally suggested by Eric – instead of only adding a module and its commit pointer, you’ll add the repository and all of its commit history into your own git repository, as sub tree with directories and files. This also solves the problem that remote repositories might be gone, unreachable, or anything else hindering the successful clone.
There are several options like to squash the history into a single commit (like one would use git rebase) when adding a new subtree.

Add a subtree

When I was working on the Graphite/Grafana integration into the icinga2x box, I’ve just added the Grafana puppet module. The –prefix parameter defines the root directory for the cloned repository, then add the remote url, the branch and let it squash the entire commit history (–squash).
Git doesn’t like uncommitted changes so make sure to stash/commit any existing changes before adding a new subtree.

git subtree add --prefix modules/grafana master --squash

This results into two new commits:

commit 0b3e0c215e3021696fce3a37eff3274c174348a8
Merge: 482dc29 6d6fd37
Author: Michael Friedrich <>
Date:   Sat Nov 14 18:47:39 2015 +0100
    Merge commit '6d6fd37ec971314d820c210a50587b9d4ca2124b' as 'modules/grafana'
commit 6d6fd37ec971314d820c210a50587b9d4ca2124b
Author: Michael Friedrich <>
Date:   Sat Nov 14 18:47:39 2015 +0100
    Squashed 'modules/grafana/' content from commit 89fe873
    git-subtree-dir: modules/grafana
    git-subtree-split: 89fe873720a0a4d2d3c4363538b0fa5d71542f41


Update a subtree

In case the remote repository should be updated to incorporate the latest and greatest fixes, you can just use “git subtree pull”. You’ll need the repository url (that is merely why it is documented in inside the Vagrant box project).

$ git subtree pull --prefix modules/grafana master --squash
 * branch            master     -> FETCH_HEAD
Subtree is already at commit 89fe873720a0a4d2d3c4363538b0fa5d71542f41.


Purge a subtree

Purging a git subtree is also fairly easy – just remove the directory and commit the change. There are no additional config settings to purge unlike known from git submodules.
If you want to get more in-depth insights into Git make sure to check out the new Git training 🙂

Michael Friedrich
Michael Friedrich
Senior Developer

Michael ist seit vielen Jahren Icinga-Entwickler und hat sich Ende 2012 in das Abenteuer NETWAYS gewagt. Ein Umzug von Wien nach Nürnberg mit der Vorliebe, österreichische Köstlichkeiten zu importieren - so mancher Kollege verzweifelt an den süchtig machenden Dragee-Keksi und der Linzer Torte. Oder schlicht am österreichischen Dialekt der gerne mit Thomas im Büro intensiviert wird ("Jo eh."). Wenn sich Michael mal nicht in der Community helfend meldet, arbeitet er am nächsten LEGO-Projekt oder geniesst...

Improved NodeJS Events durch Cluster …

… jeder von euch kennt das Problem, der Kollege kommt um die Ecke und möchte wenn möglich sofort, dass ein neues geiles Tools mit in den Infra Stack aufgenommen wird, gesagt getan.
In diesem Bespiel eine besonders cooles in NodeJS geschriebenes Dashboard für… lass es hier ein DockerManagement Tool sein. Dabei stößt man bei der großen Akzeptanz durch die Kollegen, auch auf einmal auf noch ganz andere Probleme (Stichwort: Performance Bottlenecks wie DDoS durch eigene Leute).
Hierbei könnte euch das NodeJS Modul Cluster behilflich sein, hier ist die Doku zu finden.
Cluster macht dabei nicht viel, es erweitert den NodeJS Stack insbesondere das Event Driven Modell von NodeJS ( so Arbeitet Google(s) v8 Engine ) um eine Art Interprocess Schnittstelle zu forked Child NodeJS Prozessen, die sich dabei Filesystem Elemente/Typen wie Sockets, Filedeskriptoren etc. teilen können und somit gemeinsam auf diesen operieren können.
Hier wollen wir eine schon bestehende Express Framework Anwendung mit einigen wenigen Zeilen Code um die Fähigkeit erweitern, dem System zur Verfügung stehenden CPU Cores effizienter ausnutzen zu können, damit sich die Events schneller abarbeiten lassen.
Ich werde hier allerdings nicht Express selber beschreiben, sondern setzte hier voraus das der Leser dieses Framework kennt. Wenn nicht könnt ihr die Infos unter diesem Link abrufen, so let’s beginn …

$ sudo -i                                  # <- da meine Workstation ein Ubuntu ist sollten wir zumindest was die Essentials sind kurz zu 'root' werden um diese Problemlos installiert zu bekommen
$ npm install express -g                   # <- installiert uns das Express Framework samt CLI Tools
express@4.13.3 /usr/lib/node_modules/express
├── escape-html@1.0.2
├── merge-descriptors@1.0.0
├── cookie@0.1.3
├── array-flatten@1.1.1
├── cookie-signature@1.0.6
├── utils-merge@1.0.0
├── content-type@1.0.1
├── fresh@0.3.0
├── path-to-regexp@0.1.7
├── content-disposition@0.5.0
├── vary@1.0.1
├── etag@1.7.0
├── serve-static@1.10.0
├── range-parser@1.0.2
├── methods@1.1.1
├── parseurl@1.3.0
├── depd@1.0.1
├── qs@4.0.0
├── on-finished@2.3.0 (ee-first@1.1.1)
├── finalhandler@0.4.0 (unpipe@1.0.0)
├── debug@2.2.0 (ms@0.7.1)
├── proxy-addr@1.0.8 (forwarded@0.1.0, ipaddr.js@1.0.1)
├── send@0.13.0 (destroy@1.0.3, statuses@1.2.1, ms@0.7.1, mime@1.3.4, http-errors@1.3.1)
├── type-is@1.6.9 (media-typer@0.3.0, mime-types@2.1.7)
└── accepts@1.2.13 (negotiator@0.5.3, mime-types@2.1.7)
$ npm install express-generator -g
/usr/bin/express -> /usr/lib/node_modules/express-generator/bin/express
express-generator@4.13.1 /usr/lib/node_modules/express-generator
├── sorted-object@1.0.0
├── commander@2.7.1 (graceful-readlink@1.0.1)
└── mkdirp@0.5.1 (minimist@0.0.8)
$ exit                                     # <- ab hier geht es ohne 'root' Rechte weiter
$ mkdir cool-app && cd cool-app            # <- Projekt Verzeichnis anlegen und in dieses wechseln
$ pwd                                      # <- vergewissern das wir uns auch in diesem wirklich befinden
$ express --git .                          # <- wir provisionieren uns unser Projekt from Scratch, dieses ist somit direkt Lauffähig ohne das wir einen Zeile Code schreiben müssen, haben hier leider keine Zeit zu 😉
   create : .
   create : ./package.json
   create : ./app.js
   create : ./.gitignore
   create : ./public
   create : ./routes
   create : ./routes/index.js
   create : ./routes/users.js
   create : ./views
   create : ./views/index.jade
   create : ./views/layout.jade
   create : ./views/error.jade
   create : ./bin
   create : ./bin/www
   create : ./public/javascripts
   create : ./public/images
   create : ./public/stylesheets
   create : ./public/stylesheets/style.css
   install dependencies:
     $ cd . && npm install
   run the app:
     $ DEBUG=cool-app:* npm start

Ab hier können wir das ganze mal kurz testen, um uns zu vergewissern das die Anwendung auch läuft ...

$ npm start
> cool-app@0.0.0 start /home/enzo/nodejsProjects/cool-app
> node ./bin/www

Nicht wundern die Applikation bleibt im Vordergrund hängen, was ist Ok ist, somit können wir diese schneller terminieren und relaunchen. Weiter geht es mit einem Test im Browser, die Anwendung lauscht standardmäßig am Port 3000, somit rufen wir hier einmal http://localhost:3000 auf und lassen uns überraschen was da so schönes kommt ...

Geil es läuft also, nun gut machen wir das ganze mit Cluster noch skalierbarer, let's go ...
Öffnet hierzu im Projekt Verzeichnis einmal die bin/www Datei, diese stellt laut package.json unseren Eintrittspunkt in die Anwendung dar, wir kopieren uns diese als Backup weg bevor wir anfangen hier Änderungen vorzunehmen.
Kommentiert bitte folgende Zeilen einmal aus ...

 * Get port from environment and store in Express.
var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);
 * Create HTTP server.
var server = http.createServer(app);
 * Listen on provided port, on all network interfaces.
server.on('error', onError);
server.on('listening', onListening);

... nun fügt ihr ab Zeile 10 bitte folgendes hinzu ...

// cluster requirements
var cluster = require('cluster');
var numCPUs = require('os').cpus().length;
if( cluster.isMaster ) {
  for( var i = 0; i < numCPUs; i++ ) {
  cluster.on( 'listening', function( worker ){
    console.log( 'worker ' + + ' is now listen for incoming connections ... ' );
  cluster.on( 'exit', function( worker, code, signal ) {
    console.log( 'worker ' + + ' died' );
} else {
    // Workers can share any TCP connection
    // In this case it is an HTTP server
    * Get port from environment and store in Express.
    var port = normalizePort(process.env.PORT || '3000');
    app.set('port', port);
    * Create HTTP server.
    var server = http.createServer(app);
    * Listen on provided port, on all network interfaces.
    server.on('error', onError);
    server.on('listening', onListening);

.. jetzt sollte das ganze auch schon funktionieren, probieren wir es doch einmal aus.

$ npm start
> cool-app@0.0.0 start /home/enzo/nodejsProjects/cool-app
> node ./bin/www
worker 31979 is now listen for incoming connections ...
worker 31974 is now listen for incoming connections ...
worker 31985 is now listen for incoming connections ...
worker 31996 is now listen for incoming connections ...
GET / 304 840.784 ms - -
GET /stylesheets/style.css 304 31.416 ms - -

Jetzt könnte man denken das sich hier nichts geändert hat, dem ist aber nicht so, der Beweis ist in der Prozess Tabelle zu finden, gucken wir doch kurz einmal hinein ...

$ ps auxf | grep node
enzo     31969  0.1  0.4 901264 33004 pts/7    Sl+  14:47   0:00          |   |       \_ node ./bin/www
enzo     31974  0.1  0.4 901256 32324 pts/7    Sl+  14:47   0:00          |   |           \_ /usr/bin/nodejs /home/enzo/nodejsProjects/cool-app/bin/www
enzo     31979  0.4  0.6 946192 47560 pts/7    Sl+  14:47   0:01          |   |           \_ /usr/bin/nodejs /home/enzo/nodejsProjects/cool-app/bin/www
enzo     31985  0.1  0.4 902668 32736 pts/7    Sl+  14:47   0:00          |   |           \_ /usr/bin/nodejs /home/enzo/nodejsProjects/cool-app/bin/www
enzo     31996  0.1  0.4 901256 32168 pts/7    Sl+  14:47   0:00          |   |           \_ /usr/bin/nodejs /home/enzo/nodejsProjects/cool-app/bin/www

Whoop whoop, 4 neue NodeJS Prozesse die hier ihre Arbeit verrichten, somit lassen sich auch die beschäftigsten Web Anwendungen wieder beschleunigen.
Das ist aber nur der Anfang wie sich NodeJS Applications aller Art verbessern lassen, für weiter Themen habe ich heute allerdings keine Zeit daher heben wir uns den Rest einfach für ein anderes mal auf.
Ich wünsche euch hiermit noch viel Spaß, ich hoffe ihr habt nun mehr Lust auf NodeJS bekommen.