package workercluster import "encoding/json" // EntryType enumerates the kinds of replicated log entries the FSM // understands. Every log entry committed through the Raft Apply path // carries an Entry of one of these kinds. // // The set is the subset from plan section 6.2 that this implementation // actually exercises today. The remaining kinds are defined in // distworker/entries.go placeholders (ObserverSetUpdate, IncidentObserve, // ...) so later phases can add Apply branches without a wire-format // churn. type EntryType string const ( // EntryConfigAdopt installs a new adopted critical-check list // into the FSM. Replaces any previously adopted list. EntryConfigAdopt EntryType = "config.adopt" // EntryObserverSetUpdate installs a new observer set with a // version stamp. EntryObserverSetUpdate EntryType = "observer_set.update" // EntryMembershipProposeAdd appends a Member to the membership // cache. The Raft library itself handles the voter promotion; the // FSM just keeps a denormalized mirror. EntryMembershipProposeAdd EntryType = "membership.propose_add" // EntryMembershipDemote flips a voter's role to observer. EntryMembershipDemote EntryType = "membership.demote" // EntryMembershipRemove drops a Member from the membership cache. EntryMembershipRemove EntryType = "membership.remove" // EntryIncidentObserve appends one observer vote for a check. EntryIncidentObserve EntryType = "incident.observe" // EntryIncidentTransition records a state transition produced by // the FSM from committed observations. EntryIncidentTransition EntryType = "incident.transition" // EntryOutboxEnqueue appends notification outbox metadata. EntryOutboxEnqueue EntryType = "outbox.enqueue" // EntryOutboxDelivered marks an outbox entry as delivered. EntryOutboxDelivered EntryType = "outbox.delivered" // EntryOutboxAck records a delivery ack / duplicate marker. EntryOutboxAck EntryType = "outbox.ack" // EntryPartitionReport stores the cluster's view of network // partition state. EntryPartitionReport EntryType = "partition.report" // EntryDiagnosticsUpdate stores per-worker health metadata. EntryDiagnosticsUpdate EntryType = "diagnostics.update" ) // Entry is the wire format the FSM expects on every Apply. The Data // field holds the JSON-encoded payload of the matching struct. type Entry struct { Type EntryType `json:"type"` Term uint64 `json:"term,omitempty"` Index uint64 `json:"index,omitempty"` ActorID string `json:"actor_id,omitempty"` Version uint64 `json:"version,omitempty"` Adopted json.RawMessage `json:"adopted,omitempty"` Set json.RawMessage `json:"set,omitempty"` Member json.RawMessage `json:"member,omitempty"` State json.RawMessage `json:"state,omitempty"` Observe json.RawMessage `json:"observe,omitempty"` Outbox json.RawMessage `json:"outbox,omitempty"` OutboxID uint64 `json:"outbox_seq,omitempty"` Report json.RawMessage `json:"report,omitempty"` Diag json.RawMessage `json:"diag,omitempty"` } // ConfigAdoptPayload is the body of an EntryConfigAdopt entry. type ConfigAdoptPayload struct { Version uint64 `json:"version"` Actor string `json:"actor"` Checks []CriticalCheckConfig `json:"checks"` } // ObserverSetPayload is the body of an EntryObserverSetUpdate entry. type ObserverSetPayload struct { Set ObserverSet `json:"set"` } // MemberPayload is the body of an EntryMembershipProposeAdd, // EntryMembershipDemote, and EntryMembershipRemove entries. type MemberPayload struct { Member Member `json:"member"` Reason string `json:"reason,omitempty"` Prev *Member `json:"prev,omitempty"` // populated on demote/remove } // IncidentObservePayload is one observer vote for a check. type IncidentObservePayload struct { CheckID int64 `json:"check_id"` WorkerID string `json:"worker_id"` Label string `json:"label"` // ok | warn | down | unknown ObservedIx uint64 `json:"observed_at_index"` } // IncidentTransitionPayload is the FSM-produced state transition // recorded after a quorum rule fires. type IncidentTransitionPayload struct { CheckID int64 `json:"check_id"` State IncidentState `json:"state"` Reason string `json:"reason,omitempty"` } // OutboxPayload is the body of an EntryOutboxEnqueue entry. type OutboxPayload struct { Entry OutboxMeta `json:"entry"` } // OutboxUpdatePayload is the body of EntryOutboxDelivered and // EntryOutboxAck entries. type OutboxUpdatePayload struct { Seq uint64 `json:"seq"` State string `json:"state"` Attempts int `json:"attempts"` LastError string `json:"last_error,omitempty"` } // PartitionReportPayload is the body of an EntryPartitionReport entry. type PartitionReportPayload struct { State PartitionState `json:"state"` } // DiagnosticsPayload is the body of an EntryDiagnosticsUpdate entry. type DiagnosticsPayload struct { Diag WorkerDiagnostics `json:"diag"` } // EncodeEntry marshals a fully-populated Entry to JSON bytes ready to // hand to raft.Apply. func EncodeEntry(e *Entry) ([]byte, error) { return json.Marshal(e) } // DecodeEntry parses Entry bytes back into the wire struct. func DecodeEntry(b []byte) (Entry, error) { var e Entry if err := json.Unmarshal(b, &e); err != nil { return e, err } return e, nil }