Rework HA job queue entry claiming & add concurrent processing - #487
Open
yhabteab wants to merge 1 commit into
Open
Rework HA job queue entry claiming & add concurrent processing#487yhabteab wants to merge 1 commit into
yhabteab wants to merge 1 commit into
Conversation
yhabteab
force-pushed
the
rework-event-queue-table
branch
4 times, most recently
from
August 17, 2026 11:57
471ec83 to
9e47b1b
Compare
Member
Author
|
Added some basic enqueueing and dequeueing test cases for the new job queue processing logic now. The tests require #489 though. |
yhabteab
force-pushed
the
db-test-env-loading
branch
2 times, most recently
from
August 17, 2026 12:43
40d1c11 to
17c2d6b
Compare
yhabteab
force-pushed
the
rework-event-queue-table
branch
from
August 17, 2026 12:52
9e47b1b to
08f78a1
Compare
yhabteab
force-pushed
the
db-test-env-loading
branch
from
August 18, 2026 07:14
17c2d6b to
4f35801
Compare
yhabteab
force-pushed
the
rework-event-queue-table
branch
3 times, most recently
from
August 18, 2026 07:58
4e6e85f to
04338b7
Compare
yhabteab
force-pushed
the
db-test-env-loading
branch
from
August 26, 2026 10:24
4f35801 to
d30ecf8
Compare
yhabteab
force-pushed
the
rework-event-queue-table
branch
from
August 27, 2026 09:44
04338b7 to
ee65cde
Compare
yhabteab
requested review from
nilmerg and
oxzi
and removed request for
nilmerg
August 27, 2026 11:50
Member
Author
|
This is the baseline for #493. I've tested both of them extensively and my dev setup is also using this branch and works fine. PS: most of the code changes are new tests for job queue enqueueing and processing logic. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR reworks the existing event queue processing logic to allow for more generic and concurrent processing of job queue entries. The existing logic was tightly coupled to the
Eventtype and its processing, which made it difficult to extend the queue processing to other types of jobs in the future, such as Icinga Notifications quick actions. For this reason, the existing logic has been refactored to allow for more generic processing of job queue entries as discussed offline with @nilmerg and @BastianLedererIcinga.First and foremost, the database queueing table is no longer called
event_queue, but ratherjob_queue, and itsJsoncolumn has been replaced with a versioned, typedenvelopecolumn, so the table can eventually carry different types of jobs in the future. As a consequence, theobject_idanduser_agentcolumns have been completely removed. Object identity is now computed at processing time based on the job type and its payload, and the user agent is replaced by the aforementioned typed envelope, which can carry any metadata that is relevant to the job type.Now, since we no longer have
object_idin the job queue table, we can no longer use it to claim and lock a job queue entry for processing. Instead, a newjob_processing_locktable has been introduced, which is used exclusively by Icinga Notifications to claim and lock a job queue entry and its associated object for processing. The table's primary keyobject_idcolumn, and a unique and not nullablejob_queue_idreferencing thejob_queuetable, provides the same guarantees as the previously used LEFT JOIN andobject_idbased locking mechanism. So, this inevitably leads to refactoring the existing job queue entry claiming and locking logic, and has now two main phases:Event). If the conversion fails, the job queue entry is marked as failed and skipped. If the conversion succeeds, it computes the object identity of the job and tries insert a row into thejob_processing_locktable. If the insert succeeds, it then compares and updates the job queue entry's state toprocessingand streams the claimed job to a channel for concurrent processing. If the INSERT IGNORE affects zero rows, it means that the object is already being locked by another worker, so the tx is rolled back and the job queue entry is skipped. Though, the compare and update of the job queue entry's state toprocessingcan fail too, if we race and lose to another worker that has just claimed the job queue entry. In that case, the tx is rolled back and the job queue entry is skipped as well. All of this, except the plain select of the batch of job queue entries, is done in a single tx without using SERIALIZABLE isolation level.job_processing_lockrow is deleted. If the processing fails, the job queue entry is marked as failed, and the associatedjob_processing_lockrow is deleted as well. The only time that we might leave a locked job and its associatedjob_processing_lockrow is when the worker panics or Icinga Notifications shuts down unexpectedly, in which case the existingretention.ResetPrunerwill eventually reset the job queue entry's state to pending and delete the associatedjob_processing_lockrow, so the job can be retried later.Example of the new envelope structure for an
Eventjob queue entry:{"version":1,"format":"event","payload":{"source_id":1,"id":"icinga-master2.devlab.com: ssh!1786712186500","name":"icinga-master2.devlab.com: ssh","url":"https://watchtower.devlab.com/icingaweb/icingadb/service?name=ssh\u0026host.name=icinga-master2.devlab.com","tags":{"environment":"0162e462daea7c02249e1995a7fff030c776380f","host":"icinga-master2.devlab.com","service":"ssh"},"severity":"warning","message":"connect to address icinga-master1.devlab.com and port 80: Connection refused HTTP CRITICAL - Unable to open TCP socket","muted":false,"muted_reason":"Checkable is not muted (no active downtime, no acknowledgement, and not flapping)","incident":true,"complete_relations":["object.type","host.name","host.display_name","services[*].name","services[*].display_name"],"relations":{"host":{"display_name":"icinga-master2.devlab.com","name":"icinga-master2.devlab.com"},"object":{"type":"service"},"services":[{"display_name":"ssh","name":"ssh"}]}}} {"version":1,"format":"event","payload":{"source_id":1,"id":"icinga-master2.devlab.com: swap!1786712202311","name":"icinga-master2.devlab.com: swap","url":"https://watchtower.devlab.com/icingaweb/icingadb/service?name=swap\u0026host.name=icinga-master2.devlab.com","tags":{"environment":"0162e462daea7c02249e1995a7fff030c776380f","host":"icinga-master2.devlab.com","service":"swap"},"severity":"crit","message":"SWAP CRITICAL - 0% free (0MB out of 0MB) - Swap is either disabled, not present, or of zero size. ","muted":false,"muted_reason":"Checkable is not muted (no active downtime, no acknowledgement, and not flapping)","incident":true,"complete_relations":["object.type","host.name","host.display_name","services[*].name","services[*].display_name"],"relations":{"host":{"display_name":"icinga-master2.devlab.com","name":"icinga-master2.devlab.com"},"object":{"type":"service"},"services":[{"display_name":"swap","name":"swap"}]}}}Why removing the
object_idcolumn from the job queue table?In the previous implementation, the
object_idwas populated by the listener when the job queue entry was enqueued, and it was of course used to claim and lock the job queue entry for processing. However, having theobject_idin the job queue table limits each and every job queue entry to be associated with a single object, and of course, it requires every client to pre-compute the object identity before enqueuing. Till now, this was not a problem because the only client that was enqueuing jobs, was the Icinga Notifications listener, which is aware of the object identity. However, with #450, Icinga Notifications Web will also be able to enqueue jobs for quick actions that are very different from the existing and more complex events. As opposed to events, quick actions can be batched for multiple objects/incidents, and having theobject_idin the job queue table would not make sense anymore, because a single job queue entry can target multiple objects (not yet supported, but is planned for the future). So, Icinga Notifications Web will have to scan theobject_id_tagstable to determine the complete list of tags, compute the object ID for each object, and then enqueue a separate job queue entry for each of them. According to @nilmerg, this slows down the UI interactions dramatically, and wants to avoid in any way possible. Consequently, it was decided to remove theobject_idcolumn from the job queue table, and instead let the job enqueuer (whoever that is) to just provide the id tags in its payload, and let Icinga Notifications do the heavy lifting.