Drop the "-source" suffix from the configuration option. Furhtermore,
with the latest IGL release 0.8.1[0], the "api-base-url" is renamed to
just "url".
[0]: https://github.com/Icinga/icinga-go-library/pull/168
Allow configurable timeouts for the StreamSorter, to set them to a
fraction of their default for the tests. Now the tests are done in three
seconds instead of three minutes.
While doing so, another race condition with the test logging was
unveiled. Since this race results from a closing test context and test
logger, there was not much to do and I decided to just drop the logging
message, which was used only for tests anyway.
The whole StreamSorter logic is only required for Icinga Notifications.
Thus, the implementation was moved from the history package to the
notifications package, removing some unnecessary generalizations on the
way. This results in big changes to be made in the notifications
package, while other modules are mostly not affected.
The parameters can not only be strings, but anything to PHP's liking. In
one example, an integer was observed. Since Parameters is converted to
an []any later anyways, this is no real change in behavior.
After Julian reworked big parts of the StreamSorter for the better, I
went over the code multiple times and added a few comments for parts I
had to read twice.
Within the tests, there might be a data race when zaptest is used after
the test's context is done. Since there were a few log messages
potentially occurring after the test's end, a guard was added to ensure
no verbose log messages are being produced if the context is done.
This commit is pretty much an overhaul of the implementation to allow for a
more straight-forward way to close the output channel. The main changes to the
implementation are:
- StreamSorter now provides a method PipelineFunc that can directly be used in
a history sync pipeline. This allows StreamSorter to handle the in + out
stream pair internally, so that it closes out after in was closed and all
messages from it were passed to out.
- The two worker goroutines were combined into a single one and the secondary
queue was removed. All pending messages remain in the heap and will only be
removed from the heap when they are about to be passed to the callback.
- The worker now handles all operations (send and close) on the output stream.
Introduce the StreamSorter.CloseOutput method to remove all submissions
for a certain output channel from both workers before closing the
channel.
The motivation behind this change is to have a single point where the
output channel is closed while no submissions are being sent into an
already closed channel.
- Store the streamSorterSubmission submission time as a time.Time
instead of a nanosecond timestamp, comparing the time.Timer's
monotonic clock.
- Replace time-based buckets in StreamSorter.submissionWorker by a heap
to be pushed and popped. However, only submissions of a certain age
are being forwarded. Reduces complexity quite a bit.
- Reduce complexity of StreamSorter.queueWorker by getting rid of
unnecessary channel signals by checking for new queue events for
processing at the loop start.
With parseRedisStreamId being in the "hot path", the quite simple
regular expression was exchanged with an even simpler string split.
However, as network operations precede and follow this, the benefit of
this optimization might be questionable.
- Ignore the "config" part of the JSON struct which is only relevant for
Icinga DB Web.
- Remove unnecessary string conversions.
- Small code changes/improvements.
Rework the prior custom variable fetching code to no longer fetch
everything in a looping fashion from Redis, but send SQL queries for
custom variables now.
In addition, for service objects now contain both the service and host
custom variables, prefixed by "host.vars." or "service.vars.".
The StreamSorter was added to history, allowing to collect messages from
multiple Redis streams, sorting them based on the timestamp in the
Stream ID, and ejecting them back.
This is used for the callback stage, required by Icinga Notification. In
the Notification context, an ordered stream is required.
Despite my best intention, it felt like I have created an Erlang.
After reintroducing Event.ExtraTags in the IGL and Icinga Notifications,
Icinga DB populates events by their custom variables.
At the moment, the required customvars are fetched from Redis for each
event. Due to the Redis schema, at least on HGETALL with manual
filtering is required. This might be a good candidate for further
caching, and cache invalidation.
- Don't validate notifications config in a background Goroutine.
- Clip pipeline slice to avoid reusing capability twice.
- Rework notification Client.buildCommonEvent and depending methods.
- Resubmit events after updating rules in one go.
- Simplify Client.fetchHostServiceName based on Julian's suggestion.
Co-Authored-By: Julian Brost <julian.brost@icinga.com>
When a faulty - like syntactical incorrect - object filter expression
was loaded, each evaluation fails. However, prior to this change, the
submission logic was exited, making Icinga DB unable to recover. Now,
the event will be considered as no rule has matched and new rule version
can be loaded.
There is no need to let each Icinga Notifications source know the root
URL of Icinga Web 2. Since the latest IGL and IN change, partly URLs
relative to Icinga Web 2 are supported.
Do not silently drop failing callback submissions - such as Icinga
Notification during restarts or network disruptions -, but switch the
internal makeCallbackStageFunc stageFunc into a backlog mode.
This resulted in multiple changes, including removing the background
worker for notifications.Client, as otherwise the event submission
status could not be propagated back.
- Bump IGL to latest changes in Icinga/icinga-go-library#145.
- Allow specifying which pipeline keys are relevant, ignore others.
- Allow specifying which pipeline key should be parsed in which type.
- Create history.DowntimeHistoryMeta as a chimera combining
history.DowntimeHistory and history.HistoryDowntime to allow access
event_type, distinguishing between downtime_start and downtime_end.
- Trace times for submission steps in the worker. Turns out, the single
threaded worker blocks roughly two seconds for each
Client.ProcessEvent method call. This might sum up to minutes if lots
of events are processed at once. My current theory is that the delay
results in the expensive bcrypt hash comparison on Notifications.
Instead of retrieving the host and service names from the used RDBMs,
this commit allows us to query them from Redis. This is done to avoid
the overhead of database queries, especially when the host and service
names are always to be found in Redis. The previous implementation
simply perfomed two database queries with each received entity based on
their IDs, but we can perform this operation more efficiently from Redis
using the same filtering logic as before. Of course, we now have to
maintain more code needed to handle the Redis operations, but this is a
trade-off we should be willing to make for performance reasons.
Otherwise, posting the entity in a `go s.Submit(entity)`
manner in the background will mess up the order of events
as there might be another even in the queue affecting the
same entity.
Apart from that, the log entry "submitted event ..." is also
downgraded to debug level, as it creates too much noise at the
info level without saying anything relevant to an end user.
Instead allow them to reference any columns of the database entity as
long as that entity provides it. It also removes the retry mechanism
used to execute the queries as this would block the worker
unnecessarily.
This is the first version to use Icinga DB as an event source for Icinga
Notifications. If configured accordingly, Icinga DB forwards events
crafted from the Redis pipeline to the Icinga Notifications API.
This required a small refactoring of the history synchronization to
allow hooking into the Redis stream. Afterwards, the newly introduced
notifications package handles the rest.
Note: As part of this architectural change, Icinga Notifications offers
filters to be evaluated by Icinga DB. At the moment, these are SQL
queries being executed on the Icinga DB relational database. Either
consider both Icinga DB and Icinga Notifications to be part of the same
trust domain or consider the security implications.
Furthermore, this change requires a change on Icinga Notifications as
well. This will not work with the current version 0.1.1.