github.com/asynkron/protoactor-go@v0.0.0-20240308120642-ef91a6abee75/cluster/identitylookup/disthash/manager.go (about)

     1  package disthash
     2  
     3  import (
     4  	"log/slog"
     5  	"time"
     6  
     7  	"github.com/asynkron/protoactor-go/actor"
     8  	clustering "github.com/asynkron/protoactor-go/cluster"
     9  	"github.com/asynkron/protoactor-go/eventstream"
    10  )
    11  
    12  const (
    13  	PartitionActivatorActorName = "partition-activator"
    14  )
    15  
    16  type Manager struct {
    17  	cluster        *clustering.Cluster
    18  	topologySub    *eventstream.Subscription
    19  	placementActor *actor.PID
    20  	rdv            *clustering.Rendezvous
    21  }
    22  
    23  func newPartitionManager(c *clustering.Cluster) *Manager {
    24  	return &Manager{
    25  		cluster: c,
    26  		rdv:     clustering.NewRendezvous(),
    27  	}
    28  }
    29  
    30  func (pm *Manager) Start() {
    31  	pm.cluster.Logger().Info("Started partition manager")
    32  	system := pm.cluster.ActorSystem
    33  
    34  	activatorProps := actor.PropsFromProducer(func() actor.Actor { return newPlacementActor(pm.cluster, pm) })
    35  	pm.placementActor, _ = system.Root.SpawnNamed(activatorProps, PartitionActivatorActorName)
    36  	pm.cluster.Logger().Info("Started partition placement actor")
    37  
    38  	pm.topologySub = system.EventStream.
    39  		Subscribe(func(ev interface{}) {
    40  			if topology, ok := ev.(*clustering.ClusterTopology); ok {
    41  				pm.onClusterTopology(topology)
    42  			}
    43  		})
    44  }
    45  
    46  func (pm *Manager) Stop() {
    47  	system := pm.cluster.ActorSystem
    48  	system.EventStream.Unsubscribe(pm.topologySub)
    49  
    50  	err := system.Root.PoisonFuture(pm.placementActor).Wait()
    51  	if err != nil {
    52  		pm.cluster.Logger().Error("Failed to shutdown partition placement actor", slog.Any("error", err))
    53  	}
    54  
    55  	pm.cluster.Logger().Info("Stopped PartitionManager")
    56  }
    57  
    58  func (pm *Manager) PidOfActivatorActor(addr string) *actor.PID {
    59  	return actor.NewPID(addr, PartitionActivatorActorName)
    60  }
    61  
    62  func (pm *Manager) onClusterTopology(tplg *clustering.ClusterTopology) {
    63  	pm.cluster.Logger().Info("onClusterTopology", slog.Uint64("topology-hash", tplg.TopologyHash))
    64  
    65  	for _, m := range tplg.Members {
    66  		pm.cluster.Logger().Info("Got member", slog.Any("member", m))
    67  	}
    68  
    69  	pm.rdv = clustering.NewRendezvous()
    70  	pm.rdv.UpdateMembers(tplg.Members)
    71  	pm.cluster.ActorSystem.Root.Send(pm.placementActor, tplg)
    72  }
    73  
    74  func (pm *Manager) Get(identity *clustering.ClusterIdentity) *actor.PID {
    75  	ownerAddress := pm.rdv.GetByClusterIdentity(identity)
    76  
    77  	if ownerAddress == "" {
    78  		return nil
    79  	}
    80  
    81  	identityOwnerPid := pm.PidOfActivatorActor(ownerAddress)
    82  	request := &clustering.ActivationRequest{
    83  		ClusterIdentity: identity,
    84  		RequestId:       "",
    85  	}
    86  	future := pm.cluster.ActorSystem.Root.RequestFuture(identityOwnerPid, request, 5*time.Second)
    87  	res, err := future.Result()
    88  	if err != nil {
    89  		return nil
    90  	}
    91  	typed, ok := res.(*clustering.ActivationResponse)
    92  	if !ok {
    93  		return nil
    94  	}
    95  	return typed.Pid
    96  }