153 строки
5.3 KiB
Go
153 строки
5.3 KiB
Go
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
|
|
}
|