Skip to content

Deleting things that FM creates during execution #10248

@smklein

Description

@smklein

The Task

Currently, our FM system creates sitreps, and later in an execution phase, does a bunch of work in a background rendezvous task.

This task is responsible for creating and updating database state ("Go create an alert", "Go create a support bundle"), and will also be responsible for updating SP and sled state ("go turn on these LEDs", "Go tell a host OS that we can drop a fault from fmdump").

It should also be the responsibility of the FM system and rendezvous task to delete objects which it creates.

The Problem

However, because distributed systems, this isn't as simple as "create the object if it's in the sitrep, delete if it isn't in the sitrep".

Sitrep execution happens within each Nexus, and each Nexus can be executing an arbitrarily-old sitrep.

Suppose we have the following scenario:

  • Nexus A, executing sitrep 100: "Create alert A"
  • Nexus B, executing sitrep 101: "Delete alert A"

If these executed sequentially: great, everything works. However, because these are different processes, running on different machines, we could have the ordering of:

  • Nexus A executes sitrep 100 (creates A)
  • Nexus B executes sitrep 101 (deletes A)
  • Nexus A executes sitrep 100 again - A is re-created as a zombie alert. This would be bad!

The Fix

There are several, with various pros/cons

Just use a transaction

Basically: Only do the object creation if the "sitrep we're executing is still the target sitrep"
Pros: Simple
Cons: High contention. Can block new sitrep insertion behind execution.

Tombstones

If we delete an object from the DB, leave behind a tombstone indicating it was removed, to prevent it from being re-created.
Pros: Simple, low-contention, straightforward
Cons: When can we remove the tombstones?

Generation numbers

When updating a database row - like "fm_alert" - create an auxiliary table which is called something like "fm_alert_metadata". This table should contain the generation number of the sitrep (or an equivalent "only increasing" generation for the set of alerts emitted by that sitrep).

When creating alerts, we only proceed "if the on-disk generation is less than or equal to that of our currently-executing sitrep". Otherwise, we know we're trying to do old work, and bail out immediately. The "check generation + create" operations should happen transactionally. Once we've finished with the "creation" steps, we could update the on-disk generation number.

Pros: Low contention.
Cons: Adds boilerplate, a little tricky to get right with pagination

Metadata

Metadata

Assignees

Labels

fault-managementEverything related to the fault-management initiative (RFD480 and others)

Type

No fields configured for Task.

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions