Today I show you a snapshot of my daily work. It is especially interesting this time, because it’s a not-so simple problem to solve. It’s not difficult per se, but involves quite some understanding of the Icinga Web 2 framework and how it communicates with the web server.
Disclaimer: What I’m going to show, is not a feature preview or anything. It’s more of a proof of concept, and it may be that forever and won’t be continued further.
Those of you who follow the development of Icinga DB already know that Redis plays an integral part in the architectural design. Icinga DB Web also accesses Redis to retrieve up-to-date volatile information. This currently applies to state information. For every host or service that is shown in the UI, Icinga DB Web also fetches the state of these objects from Redis before presenting you the result. However, this also means one to two additional network round trips are being made for each client request. Primarily it’s the database that is contacted multiple times, but on top of that comes Redis. And in case Redis isn’t running on the same machine as the web server, which is highly likely in production environments, it means an additional delay before a client gets the result.
The states are also in the database, but may not necessarily be as up-to-date as those from Redis. But in the best case, we’re talking of a few seconds difference here. This itself isn’t much of an issue. But when does this matter?
To answer that, I first have to list the various presentation modes that are available: Web Browser, PDF export, JSON export, CSV export
Looking at those, I’d identify only one that really benefits from up-to-date information: The web browser. All others only show a snapshot of data from the time the export was initiated at. It doesn’t matter if the information is 0.1, 2 or 10 seconds old. It will be old anyway when looking at the result.
So it’s only what we’ll show in the web browser that may be of interest to be as recent as possible. And that will probably be only something that changes frequently, such as states. Configuration rarely changes that often as states.
If only states (available in Redis) need to be up-to-date in the browser but configuration doesn’t (available in the database), let’s decouple the auto refresh! A service list for example still auto-refreshes regularly, but it doesn’t have to do that every 10 seconds. Five minutes might be enough. The state information however, may still be refreshed every 10 seconds.
And remember, by doing that we’ll only contact the database every five minutes. In case of complex restrictions or filters this can be quite a difference in terms of load on the database.
To achieve this, the following is needed:
- Raise autorefresh interval of services/index to five minutes
- Store in session what the user is looking at
- Refresh output of services every 10th second
- Add a controller to provide updates for service output only
- Add a JS behavior that initiates the independent refreshes
Raise autorefresh interval of services/index to five minutes
That was easy, wasn’t it?
Store in session what the user is looking at
Ah, session storage, also quite easy if you know how to access it. Here, I use a dedicated namespace to not pollute the main session. The “what the user is looking at” is identified by the relative request path. (e.g. icingadb/services)
It is placed in the postDispatch method of the base controller used in Icinga DB Web. It is called after an action has been dispatched.
Refresh output of services every 10th second
The change also registers data attributes for the host and service ID. These are needed later on to fetch their states from Redis.
Add a controller to provide updates for service output only
This is the endpoint that is utilized to partially update the ServiceList widget. It accesses Redis to fetch the current states.
Also, it performs an asynchronous content update, a feature that is available since Icinga Web 2 v2.8.0. This allows to update particular elements in the view, instead of the entire view.
Add a JS behavior that initiates the independent refreshes
This is the heart of the implementation. Without scripting on the client, such specific autorefreshes are not possible.
It’s still an ordinary behavior. Though, it uses ES6 features and hence is not compatible with IE or Edge 18.
But it’s rather simple, because it only initiates the refresh and doesn’t have to process the response, as this is done by Icinga Web 2 already.
Visiting the main service listing in Icinga DB Web now, the shown outputs are updated every 10th second. Works nice and flawlessly.
This is of course not complete. The state indicators and the last state change will now only be refreshed every five minutes. But this can be solved just like it’s been done for the output.
It is possible to decouple the auto-refresh of configuration and states. But what side-effects has this I didn’t thought of initially?
Well, you might have guessed it: Sorting and filtering.
These are not a problem as long they only reference configuration related data. For example a filter rule for a servicegroup membership or a custom variable. Or maybe a sort rule for name/display name.
But once filtering for states to only show problems, the view will get unfiltered at any time during the five minute period. The same applies when sorting after severity, the list gets unordered equally fast.
It’s a nice idea I think. And also an interesting solution. But regarding the filter and sort issues, this is unlikely to be introduced in a release for lists. But it may be of use for the detail views, who knows?