All checks were successful
CI / build (pull_request) Successful in 16s
JSON unmarshal produces map[string]interface{}, not concrete types.
Added ModelPayload and MessagePayload concrete types that implement
RuntimeModel and RuntimeMessage interfaces respectively.
The handleClusterMessage now re-marshals and unmarshals the payload
to convert from map[string]interface{} to the proper concrete type.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
176 lines
6.0 KiB
Go
176 lines
6.0 KiB
Go
package cluster
|
|
|
|
import (
|
|
"time"
|
|
)
|
|
|
|
const (
|
|
// NumShards defines the total number of shards in the cluster
|
|
NumShards = 1024
|
|
// VirtualNodes defines the number of virtual nodes per physical node for consistent hashing
|
|
VirtualNodes = 150
|
|
// Leadership election constants
|
|
LeaderLeaseTimeout = 10 * time.Second // How long a leader lease lasts
|
|
HeartbeatInterval = 3 * time.Second // How often leader sends heartbeats
|
|
ElectionTimeout = 2 * time.Second // How long to wait for election
|
|
)
|
|
|
|
// NodeStatus represents the health status of a node
|
|
type NodeStatus string
|
|
|
|
const (
|
|
NodeStatusActive NodeStatus = "active"
|
|
NodeStatusDraining NodeStatus = "draining"
|
|
NodeStatusFailed NodeStatus = "failed"
|
|
)
|
|
|
|
// NodeInfo represents information about a cluster node
|
|
type NodeInfo struct {
|
|
ID string `json:"id"`
|
|
Address string `json:"address"`
|
|
Port int `json:"port"`
|
|
Status NodeStatus `json:"status"`
|
|
Capacity float64 `json:"capacity"` // Maximum load capacity
|
|
Load float64 `json:"load"` // Current CPU/memory load
|
|
LastSeen time.Time `json:"lastSeen"` // Last heartbeat timestamp
|
|
Timestamp time.Time `json:"timestamp"`
|
|
Metadata map[string]string `json:"metadata"`
|
|
IsLeader bool `json:"isLeader"`
|
|
VMCount int `json:"vmCount"` // Number of VMs on this node
|
|
ShardIDs []int `json:"shardIds"` // Shards assigned to this node
|
|
}
|
|
|
|
// NodeUpdateType represents the type of node update
|
|
type NodeUpdateType string
|
|
|
|
const (
|
|
NodeJoined NodeUpdateType = "joined"
|
|
NodeLeft NodeUpdateType = "left"
|
|
NodeUpdated NodeUpdateType = "updated"
|
|
)
|
|
|
|
// NodeUpdate represents a node status update
|
|
type NodeUpdate struct {
|
|
Type NodeUpdateType `json:"type"`
|
|
Node *NodeInfo `json:"node"`
|
|
}
|
|
|
|
// ShardMap represents the distribution of shards across cluster nodes
|
|
type ShardMap struct {
|
|
Version uint64 `json:"version"` // Incremented on each change
|
|
Shards map[int][]string `json:"shards"` // shard ID -> [primary, replica1, replica2]
|
|
Nodes map[string]NodeInfo `json:"nodes"` // node ID -> node info
|
|
UpdateTime time.Time `json:"updateTime"`
|
|
}
|
|
|
|
// ClusterMessage represents inter-node communication
|
|
type ClusterMessage struct {
|
|
Type string `json:"type"`
|
|
From string `json:"from"`
|
|
To string `json:"to"`
|
|
Payload interface{} `json:"payload"`
|
|
Timestamp time.Time `json:"timestamp"`
|
|
}
|
|
|
|
// RebalanceRequest represents a request to rebalance shards
|
|
type RebalanceRequest struct {
|
|
RequestID string `json:"requestId"`
|
|
FromNode string `json:"fromNode"`
|
|
ToNode string `json:"toNode"`
|
|
ShardIDs []int `json:"shardIds"`
|
|
Reason string `json:"reason"`
|
|
Migrations []ActorMigration `json:"migrations"`
|
|
}
|
|
|
|
// ActorMigration represents the migration of an actor between nodes
|
|
type ActorMigration struct {
|
|
ActorID string `json:"actorId"`
|
|
FromNode string `json:"fromNode"`
|
|
ToNode string `json:"toNode"`
|
|
ShardID int `json:"shardId"`
|
|
State map[string]interface{} `json:"state"`
|
|
Version int64 `json:"version"`
|
|
Status string `json:"status"` // "pending", "in_progress", "completed", "failed"
|
|
}
|
|
|
|
// LeaderElectionCallbacks defines callbacks for leadership changes
|
|
type LeaderElectionCallbacks struct {
|
|
OnBecameLeader func()
|
|
OnLostLeader func()
|
|
OnNewLeader func(leaderID string)
|
|
}
|
|
|
|
// LeadershipLease represents a leadership lease in the cluster
|
|
type LeadershipLease struct {
|
|
LeaderID string `json:"leaderId"`
|
|
Term uint64 `json:"term"`
|
|
ExpiresAt time.Time `json:"expiresAt"`
|
|
StartedAt time.Time `json:"startedAt"`
|
|
}
|
|
|
|
// VirtualMachine defines the interface for a virtual machine instance.
|
|
// This interface provides the minimal contract needed by the cluster package
|
|
// to interact with VMs without creating import cycles with the runtime package.
|
|
type VirtualMachine interface {
|
|
// GetID returns the unique identifier for this VM
|
|
GetID() string
|
|
// GetActorID returns the actor ID this VM represents
|
|
GetActorID() string
|
|
// GetState returns the current state of the VM
|
|
GetState() VMState
|
|
}
|
|
|
|
// VMState represents the state of a virtual machine
|
|
type VMState string
|
|
|
|
const (
|
|
VMStateIdle VMState = "idle"
|
|
VMStateRunning VMState = "running"
|
|
VMStatePaused VMState = "paused"
|
|
VMStateStopped VMState = "stopped"
|
|
)
|
|
|
|
// RuntimeModel defines the interface for an EventStorming model that can be loaded into a runtime.
|
|
// This decouples the cluster package from the specific eventstorming package.
|
|
type RuntimeModel interface {
|
|
// GetID returns the unique identifier for this model
|
|
GetID() string
|
|
// GetName returns the name of this model
|
|
GetName() string
|
|
}
|
|
|
|
// RuntimeMessage defines the interface for messages that can be sent through the runtime.
|
|
// This provides type safety for inter-actor communication without creating import cycles.
|
|
type RuntimeMessage interface {
|
|
// GetTargetActorID returns the ID of the actor this message is addressed to
|
|
GetTargetActorID() string
|
|
// GetType returns the message type identifier
|
|
GetType() string
|
|
}
|
|
|
|
// ModelPayload is a concrete type for JSON-unmarshaling RuntimeModel payloads.
|
|
// Use this when receiving model data over the network.
|
|
type ModelPayload struct {
|
|
ID string `json:"id"`
|
|
Name string `json:"name"`
|
|
}
|
|
|
|
// GetID implements RuntimeModel
|
|
func (m *ModelPayload) GetID() string { return m.ID }
|
|
|
|
// GetName implements RuntimeModel
|
|
func (m *ModelPayload) GetName() string { return m.Name }
|
|
|
|
// MessagePayload is a concrete type for JSON-unmarshaling RuntimeMessage payloads.
|
|
// Use this when receiving message data over the network.
|
|
type MessagePayload struct {
|
|
TargetActorID string `json:"targetActorId"`
|
|
Type string `json:"type"`
|
|
}
|
|
|
|
// GetTargetActorID implements RuntimeMessage
|
|
func (m *MessagePayload) GetTargetActorID() string { return m.TargetActorID }
|
|
|
|
// GetType implements RuntimeMessage
|
|
func (m *MessagePayload) GetType() string { return m.Type }
|