diff --git a/actor/context.go b/actor/context.go index 4f6a760f..a6bb5b83 100644 --- a/actor/context.go +++ b/actor/context.go @@ -136,10 +136,18 @@ func (c *Context) Parent() *PID { return nil } -// Child will return the PID of the child (if any) by the given name/id. -// PID will be nil if it could not find it. +// Child will return the PID of the child (if any) by the given id. +// The id can be a relative path (e.g., "child/1") or a full path (e.g., "parent/1/child/1"). +// Returns nil if the child could not be found. func (c *Context) Child(id string) *PID { - pid, _ := c.children.Get(id) + // First try exact match (backward compatibility) + if pid, ok := c.children.Get(id); ok { + return pid + } + + // Then try with parent prefix + fullKey := c.pid.ID + pidSeparator + id + pid, _ := c.children.Get(fullKey) return pid } diff --git a/actor/context_test.go b/actor/context_test.go index 3f6ffe9c..5b0efc74 100644 --- a/actor/context_test.go +++ b/actor/context_test.go @@ -66,6 +66,11 @@ func TestSpawnChildPID(t *testing.T) { case Started: pid := c.SpawnChildFunc(childfn, "child", WithID("1")) assert.True(t, expectedPID.Equals(pid)) + + pid = c.Child("child/1") + assert.NotNil(t, pid) + assert.True(t, expectedPID.Equals(pid)) + wg.Done() case Stopped: } diff --git a/cluster/cluster_test.go b/cluster/cluster_test.go index 20a8c06d..e4332de1 100644 --- a/cluster/cluster_test.go +++ b/cluster/cluster_test.go @@ -410,6 +410,41 @@ func TestCannotDuplicateActor(t *testing.T) { c2.Stop() } +func TestClusterChildLookup(t *testing.T) { + var ( + c1Addr = getRandomLocalhostAddr() + c1 = makeCluster(t, c1Addr, "A", "eu-west") + wg = sync.WaitGroup{} + ) + + wg.Add(1) + c1.engine.SpawnFunc(func(c *actor.Context) { + switch c.Message().(type) { + case actor.Started: + childPID := c.SpawnChildFunc(func(_ *actor.Context) {}, "worker", actor.WithID("1")) + + // Test relative path lookup (new behavior) + found := c.Child("worker/1") + assert.NotNil(t, found) + assert.True(t, childPID.Equals(found)) + + // Test full path lookup (backward compatible) + fullPath := c.PID().ID + "/worker/1" + foundFull := c.Child(fullPath) + assert.NotNil(t, foundFull) + assert.True(t, childPID.Equals(foundFull)) + + assert.Equal(t, c1Addr, childPID.Address) + + wg.Done() + } + }, "parent", actor.WithID("1")) + + c1.Start() + wg.Wait() + c1.Stop() +} + func makeCluster(t *testing.T, addr, id, region string) *Cluster { config := NewConfig(). WithID(id).