implement cluster stubs: cross-node routing, rebalancing, and actor migration
CI / build (pull_request) Successful in 42s

- Fix ConsistentHashPlacement.PlaceActor() to use consistent hash ring
- Implement ConsistentHashPlacement.RebalanceShards() to redistribute shards
- Implement ClusterManager.handleRebalanceRequest() with actual rebalancing
- Implement ClusterManager.handleMigrationRequest() for actor state transfer
- Implement ClusterManager.triggerShardRebalancing() to compute and broadcast
- Implement DistributedVM.SendMessage() with cross-node NATS routing
- Implement DistributedVM.handleRebalanceRequest() to update shard map
- Fix route_message handler to check if actor is local before delivery
- Update ConsistentHashPlacement.RebalanceShards() test for new behavior
- Add handleShardMapUpdate() and broadcastShardMap() to ClusterManager
This commit is contained in:
2026-07-29 20:03:23 +02:00
parent 7487a5f3af
commit 9970c99509
4 changed files with 289 additions and 41 deletions
+53 -7
View File
@@ -4,6 +4,7 @@ import (
"context"
"encoding/json"
"fmt"
"time"
"github.com/nats-io/nats.go"
)
@@ -137,11 +138,30 @@ func (dvm *DistributedVM) LoadModel(model RuntimeModel) error {
// SendMessage routes messages across the distributed cluster
func (dvm *DistributedVM) SendMessage(message RuntimeMessage) error {
// This is a simplified implementation
// In practice, this would determine the target node based on sharding
// and route the message appropriately
actorID := message.GetTargetActorID()
targetNode := dvm.GetActorNode(actorID)
return dvm.localRuntime.SendMessage(message)
if targetNode == dvm.nodeID {
return dvm.localRuntime.SendMessage(message)
}
return dvm.routeMessageToNode(actorID, message)
}
// routeMessageToNode sends a message to another node for delivery to the target actor
func (dvm *DistributedVM) routeMessageToNode(actorID string, message RuntimeMessage) error {
msg := ClusterMessage{
Type: "route_message",
From: dvm.nodeID,
To: actorID,
Payload: MessagePayload{
TargetActorID: actorID,
Type: message.GetType(),
},
Timestamp: time.Now(),
}
return dvm.publishClusterMessage(msg)
}
// GetActorNode determines which node should handle a specific actor
@@ -199,7 +219,14 @@ func (dvm *DistributedVM) handleClusterMessage(msg *nats.Msg) {
if err := json.Unmarshal(payloadBytes, &message); err != nil {
return
}
dvm.localRuntime.SendMessage(&message)
targetActor := message.TargetActorID
if dvm.IsLocalActor(targetActor) {
dvm.localRuntime.SendMessage(&message)
} else {
// Relay to the correct node
dvm.routeMessageToNode(targetActor, &message)
}
case "rebalance":
// Handle shard rebalancing requests
@@ -209,8 +236,27 @@ func (dvm *DistributedVM) handleClusterMessage(msg *nats.Msg) {
// handleRebalanceRequest processes shard rebalancing requests
func (dvm *DistributedVM) handleRebalanceRequest(msg ClusterMessage) {
// Simplified rebalancing logic
// In practice, this would implement complex actor migration
payloadBytes, err := json.Marshal(msg.Payload)
if err != nil {
dvm.cluster.logger.Printf("Failed to marshal rebalance payload: %v", err)
return
}
var newShardMap ShardMap
if err := json.Unmarshal(payloadBytes, &newShardMap); err != nil {
dvm.cluster.logger.Printf("Failed to unmarshal shard map: %v", err)
return
}
dvm.cluster.mutex.Lock()
if newShardMap.Version > dvm.cluster.shardMap.Version {
dvm.cluster.shardMap = &newShardMap
dvm.cluster.logger.Printf("Applied new shard map (version %d) from rebalance", newShardMap.Version)
} else {
dvm.cluster.logger.Printf("Ignoring stale shard map (got version %d, current %d)",
newShardMap.Version, dvm.cluster.shardMap.Version)
}
dvm.cluster.mutex.Unlock()
}
// publishClusterMessage sends a message to other cluster nodes