Repository: Tochemey/goakt
Pull request #543 (2024-11-30 15:16:11)

refactor(enhancement): refactor the actors data structure
- Fix bugs
- Revert the DNS feature. Only IP addresses will be used due to this issues https://github.com/hashicorp/memberlist/issues/147 and https://github.com/hashicorp/memberlist/issues/162. At the moment DNS hinder cluster nodes discovery. The best option for the meantime is to set the host to "0.0.0.0" and then GoAkt will figure out the right IP address.
- Refactor the whole actors storage using a tree-like  structure
- Refactor codebase
- Remove unnecessary code
- Add two methods to `ActorSystem`: `Host` and `Port`
- Fully tested (cluster mode included)

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/Tochemey/goakt/pull/543?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Arsene) Report
Attention: Patch coverage is `84.42105%` with `74 lines` in your changes missing coverage. Please review.
> Project coverage is 86.25%. Comparing base [(`a4e7ad8`)](https://app.codecov.io/gh/Tochemey/goakt/commit/a4e7ad895dfd786244d4fc5007424c5bc1cd8d95?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Arsene) to head [(`2bf50bc`)](https://app.codecov.io/gh/Tochemey/goakt/commit/2bf50bc349ff5a212db8e8ca9f049a89201dcbb9?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Arsene).
> Report is 1 commits behind head on main.

| [Files with missing lines](https://app.codecov.io/gh/Tochemey/goakt/pull/543?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Arsene) | Patch % | Lines |
|---|---|---|
| [actors/actor\_system.go](https://app.codecov.io/gh/Tochemey/goakt/pull/543?src=pr&el=tree&filepath=actors%2Factor_system.go&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Arsene#diff-YWN0b3JzL2FjdG9yX3N5c3RlbS5nbw==) | 65.30% | [25 Missing and 9 partials :warning: ](https://app.codecov.io/gh/Tochemey/goakt/pull/543?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Arsene) |
| [actors/pid.go](https://app.codecov.io/gh/Tochemey/goakt/pull/543?src=pr&el=tree&filepath=actors%2Fpid.go&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Arsene#diff-YWN0b3JzL3BpZC5nbw==) | 85.80% | [15 Missing and 7 partials :warning: ](https://app.codecov.io/gh/Tochemey/goakt/pull/543?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Arsene) |
| [actors/pid\_tree.go](https://app.codecov.io/gh/Tochemey/goakt/pull/543?src=pr&el=tree&filepath=actors%2Fpid_tree.go&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Arsene#diff-YWN0b3JzL3BpZF90cmVlLmdv) | 90.41% | [11 Missing and 5 partials :warning: ](https://app.codecov.io/gh/Tochemey/goakt/pull/543?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Arsene) |
| [actors/pid\_node.go](https://app.codecov.io/gh/Tochemey/goakt/pull/543?src=pr&el=tree&filepath=actors%2Fpid_node.go&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Arsene#diff-YWN0b3JzL3BpZF9ub2RlLmdv) | 77.77% | [2 Missing :warning: ](https://app.codecov.io/gh/Tochemey/goakt/pull/543?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Arsene) |

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##             main     #543      +/-   ##
==========================================
- Coverage   87.00%   86.25%   -0.76%     
==========================================
  Files          46       49       +3     
  Lines        4649     4919     +270     
==========================================
+ Hits         4045     4243     +198     
- Misses        477      528      +51     
- Partials      127      148      +21     
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/Tochemey/goakt/pull/543?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Arsene).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Arsene).


Patch:
diff --git a/actors/actor_system.go b/actors/actor_system.go
index dfe4262..15d1b52 100644
--- a/actors/actor_system.go
+++ b/actors/actor_system.go
@@ -55,6 +55,7 @@ import (
 	"github.com/tochemey/goakt/v2/internal/eventstream"
 	"github.com/tochemey/goakt/v2/internal/internalpb"
 	"github.com/tochemey/goakt/v2/internal/internalpb/internalpbconnect"
+	"github.com/tochemey/goakt/v2/internal/tcp"
 	"github.com/tochemey/goakt/v2/internal/types"
 	"github.com/tochemey/goakt/v2/log"
 )
@@ -136,13 +137,19 @@ type ActorSystem interface {
 	Deregister(ctx context.Context, actor Actor) error
 	// Logger returns the logger sets when creating the actor system
 	Logger() log.Logger
+	// Host returns the actor system node host address
+	// This is the bind address for remote communication
+	Host() string
+	// Port returns the actor system node port.
+	// This is the bind port for remote communication
+	Port() int32
 	// handleRemoteAsk handles a synchronous message to another actor and expect a response.
 	// This block until a response is received or timed out.
 	handleRemoteAsk(ctx context.Context, to *PID, message proto.Message, timeout time.Duration) (response proto.Message, err error)
 	// handleRemoteTell handles an asynchronous message to an actor
 	handleRemoteTell(ctx context.Context, to *PID, message proto.Message) error
 	// setActor sets actor in the actor system actors registry
-	setActor(actor *PID)
+	broadcastActor(actor *PID)
 	// supervisor return the system supervisor
 	getSupervisor() *PID
 	// getPeerStateFromCache returns the peer state from the cache
@@ -151,6 +158,8 @@ type ActorSystem interface {
 	reservedName(nameType nameType) string
 	// getCluster returns the cluster engine
 	getCluster() cluster.Interface
+	// tree returns the actors tree
+	tree() *pidTree
 }
 
 // ActorSystem represent a collection of actors on a given node
@@ -159,8 +168,8 @@ type actorSystem struct {
 	internalpbconnect.UnimplementedRemotingServiceHandler
 	internalpbconnect.UnimplementedClusterServiceHandler
 
-	// map of actors in the system
-	actors *pidMap
+	// hold the actors tree in the system
+	actors *pidTree
 
 	// states whether the actor system has started or not
 	started atomic.Bool
@@ -249,7 +258,6 @@ func NewActorSystem(name string, opts ...Option) (ActorSystem, error) {
 	}
 
 	system := &actorSystem{
-		actors:                 newMap(),
 		actorsChan:             make(chan *internalpb.ActorRef, 10),
 		name:                   name,
 		logger:                 log.New(log.ErrorLevel, os.Stderr),
@@ -271,6 +279,7 @@ func NewActorSystem(name string, opts ...Option) (ActorSystem, error) {
 		peersStateLoopInterval: DefaultPeerStateLoopInterval,
 		port:                   0,
 		host:                   "127.0.0.1",
+		actors:                 newTree(),
 	}
 
 	system.started.Store(false)
@@ -304,6 +313,24 @@ func NewActorSystem(name string, opts ...Option) (ActorSystem, error) {
 	return system, nil
 }
 
+// Host returns the actor system node host address
+// This is the bind address for remote communication
+func (x *actorSystem) Host() string {
+	x.locker.Lock()
+	host := x.host
+	x.locker.Unlock()
+	return host
+}
+
+// Port returns the actor system node port.
+// This is the bind port for remote communication
+func (x *actorSystem) Port() int32 {
+	x.locker.Lock()
+	port := x.port
+	x.locker.Unlock()
+	return port
+}
+
 // Logger returns the logger sets when creating the actor system
 func (x *actorSystem) Logger() log.Logger {
 	x.locker.Lock()
@@ -421,12 +448,11 @@ func (x *actorSystem) Spawn(ctx context.Context, name string, actor Actor, opts
 		return nil, ErrActorSystemNotStarted
 	}
 
-	// set the default actor path assuming we are started locally
-	actorPath := x.actorAddress(name)
-	pid, exist := x.actors.Get(actorPath)
+	actorAddress := x.actorAddress(name)
+	pidNode, exist := x.actors.GetNode(actorAddress.String())
 	if exist {
+		pid := pidNode.GetValue()
 		if pid.IsRunning() {
-			// return the existing instance
 			return pid, nil
 		}
 	}
@@ -436,8 +462,10 @@ func (x *actorSystem) Spawn(ctx context.Context, name string, actor Actor, opts
 		return nil, err
 	}
 
-	x.supervisor.Watch(pid)
-	x.setActor(pid)
+	// add the given actor to the tree and supervise it
+	_ = x.actors.AddNode(NoSender, pid)
+	x.actors.AddWatcher(pid, x.supervisor)
+	x.broadcastActor(pid)
 	return pid, nil
 }
 
@@ -448,6 +476,15 @@ func (x *actorSystem) SpawnNamedFromFunc(ctx context.Context, name string, recei
 		return nil, ErrActorSystemNotStarted
 	}
 
+	actorAddress := x.actorAddress(name)
+	pidNode, exist := x.actors.GetNode(actorAddress.String())
+	if exist {
+		pid := pidNode.GetValue()
+		if pid.IsRunning() {
+			return pid, nil
+		}
+	}
+
 	config := newFuncConfig(opts...)
 	actor := newFuncActor(name, receiveFunc, config)
 	pid, err := x.configPID(ctx, name, actor, WithMailbox(config.mailbox))
@@ -455,8 +492,9 @@ func (x *actorSystem) SpawnNamedFromFunc(ctx context.Context, name string, recei
 		return nil, err
 	}
 
-	x.supervisor.Watch(pid)
-	x.setActor(pid)
+	_ = x.actors.AddNode(NoSender, pid)
+	x.actors.AddWatcher(pid, x.supervisor)
+	x.broadcastActor(pid)
 	return pid, nil
 }
 
@@ -480,15 +518,16 @@ func (x *actorSystem) Kill(ctx context.Context, name string) error {
 		return ErrActorSystemNotStarted
 	}
 
-	actorPath := x.actorAddress(name)
-	pid, exist := x.actors.Get(actorPath)
+	actorAddress := x.actorAddress(name)
+	pidNode, exist := x.actors.GetNode(actorAddress.String())
 	if exist {
+		pid := pidNode.GetValue()
 		// stop the given actor. No need to record error in the span context
 		// because the shutdown method is taking care of that
 		return pid.Shutdown(ctx)
 	}
 
-	return ErrActorNotFound(actorPath.String())
+	return ErrActorNotFound(actorAddress.String())
 }
 
 // ReSpawn recreates a given actor in the system
@@ -497,35 +536,47 @@ func (x *actorSystem) ReSpawn(ctx context.Context, name string) (*PID, error) {
 		return nil, ErrActorSystemNotStarted
 	}
 
-	actorPath := x.actorAddress(name)
-	pid, exist := x.actors.Get(actorPath)
+	actorAddress := x.actorAddress(name)
+	pidNode, exist := x.actors.GetNode(actorAddress.String())
 	if exist {
+		pid := pidNode.GetValue()
+
+		parent := NoSender
+		if parentNode, ok := x.actors.Parent(pid); ok {
+			parent = parentNode.GetValue()
+		}
+
 		if err := pid.Restart(ctx); err != nil {
-			return nil, fmt.Errorf("failed to restart actor=%s: %w", actorPath.String(), err)
+			return nil, fmt.Errorf("failed to restart actor=%s: %w", actorAddress.String(), err)
 		}
 
-		x.actors.Set(pid)
-		x.supervisor.Watch(pid)
+		// no need to handle the error here because the only time this method
+		// returns an error if when the parent does not exist which was taken care of in the
+		// lines above
+		_ = x.actors.AddNode(parent, pid)
+		x.actors.AddWatcher(pid, x.supervisor)
 		return pid, nil
 	}
 
-	return nil, ErrActorNotFound(actorPath.String())
+	return nil, ErrActorNotFound(actorAddress.String())
 }
 
 // Name returns the actor system name
 func (x *actorSystem) Name() string {
 	x.locker.Lock()
-	defer x.locker.Unlock()
-	return x.name
+	name := x.name
+	x.locker.Unlock()
+	return name
 }
 
 // Actors returns the list of Actors that are alive in the actor system
 func (x *actorSystem) Actors() []*PID {
 	x.locker.Lock()
-	pids := x.actors.List()
+	pidNodes := x.actors.Nodes()
 	x.locker.Unlock()
-	actors := make([]*PID, 0, len(pids))
-	for _, pid := range pids {
+	actors := make([]*PID, 0, len(pidNodes))
+	for _, pidNode := range pidNodes {
+		pid := pidNode.GetValue()
 		if !isReservedName(pid.Name()) {
 			actors = append(actors, pid)
 		}
@@ -557,9 +608,10 @@ func (x *actorSystem) ActorOf(ctx context.Context, actorName string) (addr *addr
 	}
 
 	// first check whether the actor exist locally
-	actorPath := x.actorAddress(actorName)
-	if lpid, ok := x.actors.Get(actorPath); ok {
+	actorAddress := x.actorAddress(actorName)
+	if lpidNode, ok := x.actors.GetNode(actorAddress.String()); ok {
 		x.locker.Unlock()
+		lpid := lpidNode.GetValue()
 		return lpid.Address(), lpid, nil
 	}
 
@@ -601,9 +653,10 @@ func (x *actorSystem) LocalActor(actorName string) (*PID, error) {
 		return nil, ErrActorSystemNotStarted
 	}
 
-	actorPath := x.actorAddress(actorName)
-	if lpid, ok := x.actors.Get(actorPath); ok {
+	actorAddress := x.actorAddress(actorName)
+	if lpidNode, ok := x.actors.GetNode(actorAddress.String()); ok {
 		x.locker.Unlock()
+		lpid := lpidNode.GetValue()
 		return lpid, nil
 	}
 
@@ -692,6 +745,8 @@ func (x *actorSystem) Stop(ctx context.Context) error {
 	if x.remotingEnabled.Load() {
 		x.remoting.Close()
 		if err := x.shutdownHTTPServer(ctx); err != nil {
+			x.reset()
+			x.logger.Errorf("%s failed to shutdown: %w", x.name, err)
 			return err
 		}
 
@@ -702,6 +757,8 @@ func (x *actorSystem) Stop(ctx context.Context) error {
 
 	if x.clusterEnabled.Load() {
 		if err := x.cluster.Stop(ctx); err != nil {
+			x.reset()
+			x.logger.Errorf("%s failed to shutdown cleanly: %w", x.name, err)
 			return err
 		}
 		close(x.actorsChan)
@@ -713,15 +770,18 @@ func (x *actorSystem) Stop(ctx context.Context) error {
 	// stop the supervisor actor
 	if err := x.getSupervisor().Shutdown(ctx); err != nil {
 		x.reset()
+		x.logger.Errorf("%s failed to shutdown cleanly: %w", x.name, err)
 		return err
 	}
+
 	// remove the supervisor from the actors list
-	x.actors.Remove(x.supervisor.Address())
+	x.actors.DeleteNode(x.supervisor)
 
+	// shutdown all actors in the system
 	for _, actor := range x.Actors() {
-		x.actors.Remove(actor.Address())
 		if err := actor.Shutdown(ctx); err != nil {
 			x.reset()
+			x.logger.Errorf("%s failed to shutdown cleanly: %w", x.name, err)
 			return err
 		}
 	}
@@ -760,12 +820,13 @@ func (x *actorSystem) RemoteLookup(ctx context.Context, request *connect.Request
 	}
 
 	addr := address.New(msg.GetName(), x.Name(), msg.GetHost(), int(msg.GetPort()))
-	pid, exist := x.actors.Get(addr)
+	pidNode, exist := x.actors.GetNode(addr.String())
 	if !exist {
 		logger.Error(ErrAddressNotFound(addr.String()).Error())
 		return nil, ErrAddressNotFound(addr.String())
 	}
 
+	pid := pidNode.GetValue()
 	return connect.NewResponse(&internalpb.RemoteLookupResponse{Address: pid.Address().Address}), nil
 }
 
@@ -807,7 +868,7 @@ func (x *actorSystem) RemoteAsk(ctx context.Context, stream *connect.BidiStream[
 		}
 
 		addr := x.actorAddress(name)
-		pid, exist := x.actors.Get(addr)
+		pidNode, exist := x.actors.GetNode(addr.String())
 		if !exist {
 			logger.Error(ErrAddressNotFound(addr.String()).Error())
 			return ErrAddressNotFound(addr.String())
@@ -818,6 +879,7 @@ func (x *actorSystem) RemoteAsk(ctx context.Context, stream *connect.BidiStream[
 			timeout = request.GetTimeout().AsDuration()
 		}
 
+		pid := pidNode.GetValue()
 		reply, err := x.handleRemoteAsk(ctx, pid, message, timeout)
 		if err != nil {
 			logger.Error(ErrRemoteSendFailure(err).Error())
@@ -870,12 +932,13 @@ func (x *actorSystem) RemoteTell(ctx context.Context, stream *connect.ClientStre
 			for request := range requestc {
 				receiver := request.GetRemoteMessage().GetReceiver()
 				addr := address.New(receiver.GetName(), x.Name(), receiver.GetHost(), int(receiver.GetPort()))
-				pid, exist := x.actors.Get(addr)
+				pidNode, exist := x.actors.GetNode(addr.String())
 				if !exist {
 					logger.Error(ErrAddressNotFound(addr.String()).Error())
 					return ErrAddressNotFound(addr.String())
 				}
 
+				pid := pidNode.GetValue()
 				if err := x.handleRemoteTell(ctx, pid, request.GetRemoteMessage()); err != nil {
 					logger.Error(ErrRemoteSendFailure(err))
 					return ErrRemoteSendFailure(err)
@@ -907,18 +970,27 @@ func (x *actorSystem) RemoteReSpawn(ctx context.Context, request *connect.Reques
 		return nil, connect.NewError(connect.CodeInvalidArgument, ErrInvalidHost)
 	}
 
-	actorPath := address.New(msg.GetName(), x.Name(), msg.GetHost(), int(msg.GetPort()))
-	pid, exist := x.actors.Get(actorPath)
+	actorAddress := address.New(msg.GetName(), x.Name(), msg.GetHost(), int(msg.GetPort()))
+	pidNode, exist := x.actors.GetNode(actorAddress.String())
 	if !exist {
-		logger.Error(ErrAddressNotFound(actorPath.String()).Error())
-		return nil, ErrAddressNotFound(actorPath.String())
+		logger.Error(ErrAddressNotFound(actorAddress.String()).Error())
+		return nil, ErrAddressNotFound(actorAddress.String())
+	}
+
+	pid := pidNode.GetValue()
+	parent := NoSender
+	if parentNode, ok := x.actors.Parent(pid); ok {
+		parent = parentNode.GetValue()
 	}
 
 	if err := pid.Restart(ctx); err != nil {
-		return nil, fmt.Errorf("failed to restart actor=%s: %w", actorPath.String(), err)
+		return nil, fmt.Errorf("failed to restart actor=%s: %w", actorAddress.String(), err)
+	}
+
+	if err := x.actors.AddNode(parent, pid); err != nil {
+		return nil, err
 	}
 
-	x.actors.Set(pid)
 	return connect.NewResponse(new(internalpb.RemoteReSpawnResponse)), nil
 }
 
@@ -937,18 +1009,18 @@ func (x *actorSystem) RemoteStop(ctx context.Context, request *connect.Request[i
 		return nil, connect.NewError(connect.CodeInvalidArgument, ErrInvalidHost)
 	}
 
-	actorPath := address.New(msg.GetName(), x.Name(), msg.GetHost(), int(msg.GetPort()))
-	pid, exist := x.actors.Get(actorPath)
+	actorAddress := address.New(msg.GetName(), x.Name(), msg.GetHost(), int(msg.GetPort()))
+	pidNode, exist := x.actors.GetNode(actorAddress.String())
 	if !exist {
-		logger.Error(ErrAddressNotFound(actorPath.String()).Error())
-		return nil, ErrAddressNotFound(actorPath.String())
+		logger.Error(ErrAddressNotFound(actorAddress.String()).Error())
+		return nil, ErrAddressNotFound(actorAddress.String())
 	}
 
+	pid := pidNode.GetValue()
 	if err := pid.Shutdown(ctx); err != nil {
-		return nil, fmt.Errorf("failed to stop actor=%s: %w", actorPath.String(), err)
+		return nil, fmt.Errorf("failed to stop actor=%s: %w", actorAddress.String(), err)
 	}
 
-	x.actors.Remove(actorPath)
 	return connect.NewResponse(new(internalpb.RemoteStopResponse)), nil
 }
 
@@ -1068,9 +1140,8 @@ func (x *actorSystem) getPeerStateFromCache(address string) (*internalpb.PeerSta
 	return peerState, nil
 }
 
-// setActor implements ActorSystem.
-func (x *actorSystem) setActor(actor *PID) {
-	x.actors.Set(actor)
+// broadcastActor broadcast the newly (re)spawned actor into the cluster
+func (x *actorSystem) broadcastActor(actor *PID) {
 	if x.clusterEnabled.Load() {
 		x.actorsChan <- &internalpb.ActorRef{
 			ActorAddress: actor.Address().Address,
@@ -1191,8 +1262,6 @@ func (x *actorSystem) enableRemoting(ctx context.Context) error {
 // reset the actor system
 func (x *actorSystem) reset() {
 	x.actors.Reset()
-	x.name = ""
-	x.cluster = nil
 }
 
 // janitor time to time removes dead actors from the system
@@ -1207,8 +1276,8 @@ func (x *actorSystem) janitor() {
 			case <-ticker.C:
 				for _, actor := range x.Actors() {
 					if !actor.IsRunning() {
-						x.logger.Infof("removing actor=%s from system", actor.Address().Name())
-						x.actors.Remove(actor.Address())
+						x.logger.Infof("janitor removing actor=%s from system", actor.ID())
+						x.actors.DeleteNode(actor)
 						if x.InCluster() {
 							if err := x.cluster.RemoveActor(context.Background(), actor.Address().Name()); err != nil {
 								x.logger.Error(err.Error())
@@ -1447,6 +1516,11 @@ func (x *actorSystem) configPID(ctx context.Context, name string, actor Actor, o
 	return pid, nil
 }
 
+// tree returns the actors tree
+func (x *actorSystem) tree() *pidTree {
+	return x.actors
+}
+
 // getCluster returns the cluster engine
 func (x *actorSystem) getCluster() cluster.Interface {
 	return x.cluster
@@ -1454,22 +1528,7 @@ func (x *actorSystem) getCluster() cluster.Interface {
 
 // reservedName returns reserved actor's name
 func (x *actorSystem) reservedName(nameType nameType) string {
-	if x.remotingEnabled.Load() {
-		return fmt.Sprintf(
-			"%s%s%s-%d-%d",
-			systemNames[nameType],
-			strings.ToTitle(x.name),
-			x.host,
-			x.port,
-			time.Now().UnixNano(),
-		)
-	}
-	return fmt.Sprintf(
-		"%s%s-%d",
-		systemNames[nameType],
-		strings.ToTitle(x.name),
-		time.Now().UnixNano(),
-	)
+	return systemNames[nameType]
 }
 
 // actorAddress returns the actor path provided the actor name
@@ -1525,27 +1584,13 @@ func (x *actorSystem) nodeLeftStateFromEvent(event *cluster.Event) (*internalpb.
 
 // setHostPort sets the host and port
 func (x *actorSystem) setHostPort() error {
+	var err error
 	// combine host and port into an hostPort string
-	hostPort := fmt.Sprintf("%s:%d", x.host, x.port)
-
-	// attempt to resolve the hostPort
-	resolvedAddr, err := net.ResolveTCPAddr("tcp", hostPort)
+	hostPort := net.JoinHostPort(x.host, strconv.Itoa(int(x.port)))
+	x.host, err = tcp.GetBindIP(hostPort)
 	if err != nil {
-		return fmt.Errorf("failed to resolve hostPort: %w", err)
-	}
-
-	// check if the original host is a DNS name or IP
-	switch {
-	case net.ParseIP(x.host) == nil:
-		// if it's a DNS name, keep the original host
-		// Only update the port from the resolved address
-		x.port = int32(resolvedAddr.Port)
-	default:
-		// if it's an IP address, update the host to the resolved IP
-		x.host = resolvedAddr.IP.String()
-		x.port = int32(resolvedAddr.Port)
+		return err
 	}
-
 	return nil
 }
 
@@ -1558,7 +1603,9 @@ func (x *actorSystem) spawnSupervisor(ctx context.Context) error {
 		return fmt.Errorf("actor=%s failed to start system supervisor: %w", actorName, err)
 	}
 
-	x.setActor(x.supervisor)
+	// set the supervisor in the tree
+	_ = x.actors.AddNode(NoSender, x.supervisor)
+	x.broadcastActor(x.supervisor)
 	return nil
 }
 
@@ -1575,9 +1622,9 @@ func (x *actorSystem) spawnRebalancer(ctx context.Context) error {
 		return fmt.Errorf("actor=%s failed to start cluster rebalancer: %w", actorName, err)
 	}
 
-	x.setActor(x.rebalancer)
-	x.rebalancer.setParent(x.supervisor)
-	x.supervisor.Watch(x.rebalancer)
+	// set the balancer in the tree with the supervisor as its parent
+	_ = x.actors.AddNode(x.supervisor, x.rebalancer)
+	x.broadcastActor(x.rebalancer)
 	return nil
 }
 
diff --git a/actors/pid.go b/actors/pid.go
index dabf9b2..6e8d91c 100644
--- a/actors/pid.go
+++ b/actors/pid.go
@@ -48,7 +48,6 @@ import (
 	"github.com/tochemey/goakt/v2/internal/errorschain"
 	"github.com/tochemey/goakt/v2/internal/eventstream"
 	"github.com/tochemey/goakt/v2/internal/internalpb"
-	"github.com/tochemey/goakt/v2/internal/slice"
 	"github.com/tochemey/goakt/v2/internal/types"
 	"github.com/tochemey/goakt/v2/log"
 )
@@ -105,15 +104,6 @@ type PID struct {
 
 	haltPassivationLnr chan types.Unit
 
-	// hold the list of actors watching the given actor
-	watchersList *slice.LockFree[*PID]
-
-	// hold the list of actors watched by this PID
-	watcheesMap *pidMap
-
-	// hold the list of the childrenMap
-	childrenMap *pidMap
-
 	// the actor system
 	system ActorSystem
 
@@ -138,7 +128,6 @@ type PID struct {
 
 	// set the metrics settings
 	restartCount   *atomic.Int64
-	childrenCount  *atomic.Int64
 	processedCount *atomic.Int64
 
 	// supervisor strategy
@@ -153,10 +142,6 @@ type PID struct {
 	processingMessages atomic.Int32
 
 	remoting *Remoting
-
-	// specifies the actor parent
-	// this field is set when this PID is a child actor
-	parent *PID
 }
 
 // newPID creates a new pid
@@ -176,10 +161,7 @@ func newPID(ctx context.Context, address *address.Address, actor Actor, opts ...
 		latestReceiveTime:     atomic.Time{},
 		haltPassivationLnr:    make(chan types.Unit, 1),
 		logger:                log.New(log.ErrorLevel, os.Stderr),
-		childrenMap:           newMap(),
 		supervisorDirective:   DefaultSupervisoryStrategy,
-		watchersList:          slice.NewLockFree[*PID](),
-		watcheesMap:           newMap(),
 		address:               address,
 		fieldsLocker:          new(sync.RWMutex),
 		stopLocker:            new(sync.Mutex),
@@ -188,7 +170,6 @@ func newPID(ctx context.Context, address *address.Address, actor Actor, opts ...
 		stashLocker:           &sync.Mutex{},
 		eventsStream:          nil,
 		restartCount:          atomic.NewInt64(0),
-		childrenCount:         atomic.NewInt64(0),
 		processedCount:        atomic.NewInt64(0),
 		processingTimeLocker:  new(sync.Mutex),
 		supervisionChan:       make(chan error, 1),
@@ -266,7 +247,8 @@ func (pid *PID) Child(name string) (*PID, error) {
 	}
 
 	childAddress := pid.childAddress(name)
-	if cid, ok := pid.childrenMap.Get(childAddress); ok {
+	if cidNode, ok := pid.system.tree().GetNode(childAddress.String()); ok {
+		cid := cidNode.GetValue()
 		if cid.IsRunning() {
 			return cid, nil
 		}
@@ -276,23 +258,35 @@ func (pid *PID) Child(name string) (*PID, error) {
 
 // Parent returns the parent of this PID
 func (pid *PID) Parent() *PID {
-	return pid.parent
+	tree := pid.ActorSystem().tree()
+	parentNode, ok := tree.Parent(pid)
+	if !ok {
+		return nil
+	}
+	return parentNode.GetValue()
 }
 
 // Children returns the list of all the direct childrenMap of the given actor
 // Only alive actors are included in the list or an empty list is returned
 func (pid *PID) Children() []*PID {
 	pid.fieldsLocker.RLock()
-	children := pid.childrenMap.List()
-	pid.fieldsLocker.RUnlock()
+	tree := pid.ActorSystem().tree()
+	pnode, ok := tree.GetNode(pid.ID())
+	if !ok {
+		pid.fieldsLocker.RUnlock()
+		return nil
+	}
 
-	cids := make([]*PID, 0, len(children))
-	for _, child := range children {
-		if child.IsRunning() {
-			cids = append(cids, child)
+	descendants := pnode.Descendants.Items()
+	cids := make([]*PID, 0, len(descendants))
+	for _, cnode := range descendants {
+		cid := cnode.GetValue()
+		if cid.IsRunning() {
+			cids = append(cids, cid)
 		}
 	}
 
+	pid.fieldsLocker.RUnlock()
 	return cids
 }
 
@@ -312,16 +306,20 @@ func (pid *PID) Stop(ctx context.Context, cid *PID) error {
 	}
 
 	pid.fieldsLocker.RLock()
-	children := pid.childrenMap
-	pid.fieldsLocker.RUnlock()
-
-	if cid, ok := children.Get(cid.Address()); ok {
+	tree := pid.system.tree()
+	if _, ok := tree.GetNode(cid.Address().String()); ok {
 		if err := cid.Shutdown(ctx); err != nil {
+			pid.fieldsLocker.RUnlock()
 			return err
 		}
+
+		// remove the node from the tree
+		tree.DeleteNode(cid)
+		pid.fieldsLocker.RUnlock()
 		return nil
 	}
 
+	pid.fieldsLocker.RUnlock()
 	return ErrActorNotFound(cid.Address().String())
 }
 
@@ -354,7 +352,7 @@ func (pid *PID) Restart(ctx context.Context) error {
 		return ErrUndefinedActor
 	}
 
-	pid.logger.Debugf("restarting actor=(%s)", pid.address.String())
+	pid.logger.Debugf("restarting actor=(%s)", pid.Name())
 
 	if pid.IsRunning() {
 		if err := pid.Shutdown(ctx); err != nil {
@@ -396,6 +394,7 @@ func (pid *PID) Restart(ctx context.Context) error {
 		)
 	}
 
+	pid.logger.Debugf("actor=(%s) successfully restarted..:)", pid.Name())
 	return nil
 }
 
@@ -407,8 +406,8 @@ func (pid *PID) RestartCount() int {
 
 // ChildrenCount returns the total number of childrenMap for the given PID
 func (pid *PID) ChildrenCount() int {
-	count := pid.childrenCount.Load()
-	return int(count)
+	descendants := pid.Children()
+	return len(descendants)
 }
 
 // ProcessedCount returns the total number of messages processed at a given time
@@ -431,18 +430,14 @@ func (pid *PID) SpawnChild(ctx context.Context, name string, actor Actor, opts .
 	}
 
 	childAddress := pid.childAddress(name)
-	pid.fieldsLocker.RLock()
-	children := pid.childrenMap
-	pid.fieldsLocker.RUnlock()
-
-	if cid, ok := children.Get(childAddress); ok {
+	tree := pid.system.tree()
+	if cnode, ok := tree.GetNode(childAddress.String()); ok {
+		cid := cnode.GetValue()
 		if cid.IsRunning() {
 			return cid, nil
 		}
 	}
 
-	pid.fieldsLocker.Lock()
-
 	// create the child actor options child inherit parent's options
 	pidOptions := []pidOption{
 		withInitMaxRetries(int(pid.initMaxRetries.Load())),
@@ -451,7 +446,6 @@ func (pid *PID) SpawnChild(ctx context.Context, name string, actor Actor, opts .
 		withEventsStream(pid.eventsStream),
 		withInitTimeout(pid.initTimeout.Load()),
 		withRemoting(pid.remoting),
-		withParent(pid),
 	}
 
 	spawnConfig := newSpawnConfig(opts...)
@@ -483,17 +477,14 @@ func (pid *PID) SpawnChild(ctx context.Context, name string, actor Actor, opts .
 	)
 
 	if err != nil {
-		pid.fieldsLocker.Unlock()
 		return nil, err
 	}
 
-	pid.childrenCount.Inc()
-	pid.childrenMap.Set(cid)
-	eventsStream := pid.eventsStream
-
-	pid.fieldsLocker.Unlock()
-	pid.Watch(cid)
+	// no need to handle the error because the given parent exist and running
+	// that check was done in the above lines
+	_ = tree.AddNode(pid, cid)
 
+	eventsStream := pid.eventsStream
 	if eventsStream != nil {
 		eventsStream.Publish(
 			eventsTopic, &goaktpb.ActorChildCreated{
@@ -505,10 +496,7 @@ func (pid *PID) SpawnChild(ctx context.Context, name string, actor Actor, opts .
 	}
 
 	// set the actor in the given actor system registry
-	if pid.ActorSystem() != nil {
-		pid.ActorSystem().setActor(cid)
-	}
-
+	pid.ActorSystem().broadcastActor(cid)
 	return cid, nil
 }
 
@@ -660,7 +648,7 @@ func (pid *PID) RemoteLookup(ctx context.Context, host string, port int, name st
 		return nil, ErrRemotingDisabled
 	}
 
-	remoteClient := pid.remoting.Client(host, port)
+	remoteClient := pid.remoting.serviceClient(host, port)
 	request := connect.NewRequest(
 		&internalpb.RemoteLookupRequest{
 			Host: host,
@@ -692,7 +680,7 @@ func (pid *PID) RemoteTell(ctx context.Context, to *address.Address, message pro
 		return err
 	}
 
-	remoteService := pid.remoting.Client(to.GetHost(), int(to.GetPort()))
+	remoteService := pid.remoting.serviceClient(to.GetHost(), int(to.GetPort()))
 
 	request := &internalpb.RemoteTellRequest{
 		RemoteMessage: &internalpb.RemoteMessage{
@@ -741,7 +729,7 @@ func (pid *PID) RemoteAsk(ctx context.Context, to *address.Address, message prot
 		return nil, err
 	}
 
-	remoteService := pid.remoting.Client(to.GetHost(), int(to.GetPort()))
+	remoteService := pid.remoting.serviceClient(to.GetHost(), int(to.GetPort()))
 
 	senderAddress := pid.Address()
 
@@ -820,7 +808,7 @@ func (pid *PID) RemoteBatchTell(ctx context.Context, to *address.Address, messag
 		)
 	}
 
-	remoteService := pid.remoting.Client(to.GetHost(), int(to.GetPort()))
+	remoteService := pid.remoting.serviceClient(to.GetHost(), int(to.GetPort()))
 
 	stream := remoteService.RemoteTell(ctx)
 	for _, request := range requests {
@@ -870,7 +858,7 @@ func (pid *PID) RemoteBatchAsk(ctx context.Context, to *address.Address, message
 		)
 	}
 
-	remoteService := pid.remoting.Client(to.GetHost(), int(to.GetPort()))
+	remoteService := pid.remoting.serviceClient(to.GetHost(), int(to.GetPort()))
 	stream := remoteService.RemoteAsk(ctx)
 	errc := make(chan error, 1)
 
@@ -916,7 +904,7 @@ func (pid *PID) RemoteStop(ctx context.Context, host string, port int, name stri
 		return ErrRemotingDisabled
 	}
 
-	remoteService := pid.remoting.Client(host, port)
+	remoteService := pid.remoting.serviceClient(host, port)
 	request := connect.NewRequest(
 		&internalpb.RemoteStopRequest{
 			Host: host,
@@ -941,7 +929,7 @@ func (pid *PID) RemoteSpawn(ctx context.Context, host string, port int, name, ac
 		return ErrRemotingDisabled
 	}
 
-	remoteService := pid.remoting.Client(host, port)
+	remoteService := pid.remoting.serviceClient(host, port)
 	request := connect.NewRequest(
 		&internalpb.RemoteSpawnRequest{
 			Host:      host,
@@ -972,7 +960,7 @@ func (pid *PID) RemoteReSpawn(ctx context.Context, host string, port int, name s
 		return ErrRemotingDisabled
 	}
 
-	remoteService := pid.remoting.Client(host, port)
+	remoteService := pid.remoting.serviceClient(host, port)
 	request := connect.NewRequest(
 		&internalpb.RemoteReSpawnRequest{
 			Host: host,
@@ -996,10 +984,10 @@ func (pid *PID) RemoteReSpawn(ctx context.Context, host string, port int, name s
 // that can be configured. All child actors will be gracefully shutdown.
 func (pid *PID) Shutdown(ctx context.Context) error {
 	pid.stopLocker.Lock()
-	pid.logger.Info("Shutdown process has started...")
+	pid.logger.Infof("shutdown process has started for actor=(%s)...", pid.Name())
 
 	if !pid.started.Load() {
-		pid.logger.Infof("Actor=%s is offline. Maybe it has been passivated or stopped already", pid.Address().String())
+		pid.logger.Infof("actor=%s is offline. Maybe it has been passivated or stopped already", pid.Name())
 		pid.stopLocker.Unlock()
 		return nil
 	}
@@ -1011,7 +999,7 @@ func (pid *PID) Shutdown(ctx context.Context) error {
 	}
 
 	if err := pid.doStop(ctx); err != nil {
-		pid.logger.Errorf("failed to cleanly stop actor=(%s)", pid.ID())
+		pid.logger.Errorf("actor=(%s) failed to cleanly stop", pid.Name())
 		pid.stopLocker.Unlock()
 		return err
 	}
@@ -1026,22 +1014,38 @@ func (pid *PID) Shutdown(ctx context.Context) error {
 	}
 
 	pid.stopLocker.Unlock()
-	pid.logger.Infof("Actor=%s successfully shutdown", pid.ID())
+	pid.logger.Infof("actor=%s successfully shutdown", pid.Name())
 	return nil
 }
 
 // Watch watches a given actor for a Terminated message when the watched actor shutdown
 func (pid *PID) Watch(cid *PID) {
-	cid.watchers().Append(pid)
-	pid.watchees().Set(cid)
+	pid.ActorSystem().tree().AddWatcher(pid, cid)
 }
 
 // UnWatch stops watching a given actor
 func (pid *PID) UnWatch(cid *PID) {
-	for index, watcher := range cid.watchers().Items() {
-		if watcher.Equals(pid) {
-			pid.watchees().Remove(cid.Address())
-			cid.watchers().Delete(index)
+	tree := pid.ActorSystem().tree()
+	pnode, ok := tree.GetNode(pid.ID())
+	if !ok {
+		return
+	}
+
+	cnode, ok := tree.GetNode(cid.ID())
+	if !ok {
+		return
+	}
+
+	for index, watchee := range pnode.Watchees.Items() {
+		if watchee.GetValue().Equals(cid) {
+			pnode.Watchees.Delete(index)
+			break
+		}
+	}
+
+	for index, watcher := range cnode.Watchers.Items() {
+		if watcher.GetValue().Equals(pid) {
+			cnode.Watchers.Delete(index)
 			break
 		}
 	}
@@ -1055,16 +1059,6 @@ func (pid *PID) Logger() log.Logger {
 	return logger
 }
 
-// watchers return the list of watchersList
-func (pid *PID) watchers() *slice.LockFree[*PID] {
-	return pid.watchersList
-}
-
-// watchees returns the list of actors watched by this actor
-func (pid *PID) watchees() *pidMap {
-	return pid.watcheesMap
-}
-
 // doReceive pushes a given message to the actor mailbox
 // and signals the receiveLoop to process it
 func (pid *PID) doReceive(receiveCtx *ReceiveContext) {
@@ -1153,7 +1147,7 @@ func (pid *PID) recovery(received *ReceiveContext) {
 // init initializes the given actor and init processing messages
 // when the initialization failed the actor will not be started
 func (pid *PID) init(ctx context.Context) error {
-	pid.logger.Info("Initialization process has started...")
+	pid.logger.Infof("initialization process has started for %s...", pid.Name())
 
 	cancelCtx, cancel := context.WithTimeout(ctx, pid.initTimeout.Load())
 	// create a new retrier that will try a maximum of `initMaxRetries` times, with
@@ -1166,7 +1160,7 @@ func (pid *PID) init(ctx context.Context) error {
 	}
 
 	pid.started.Store(true)
-	pid.logger.Info("Initialization process successfully completed.")
+	pid.logger.Infof("initialization process successfully completed for %s.", pid.Name())
 
 	if pid.eventsStream != nil {
 		pid.eventsStream.Publish(
@@ -1188,9 +1182,6 @@ func (pid *PID) reset() {
 	pid.initMaxRetries.Store(DefaultInitMaxRetries)
 	pid.latestReceiveDuration.Store(0)
 	pid.initTimeout.Store(DefaultInitTimeout)
-	pid.childrenMap.Reset()
-	pid.watchersList.Reset()
-	pid.watchees().Reset()
 	pid.behaviorStack.Reset()
 	pid.processedCount.Store(0)
 	pid.stopping.Store(false)
@@ -1199,8 +1190,14 @@ func (pid *PID) reset() {
 // freeWatchers releases all the actors watching this actor
 func (pid *PID) freeWatchers(ctx context.Context) error {
 	logger := pid.logger
-	logger.Debugf("%s freeing all watcher actors...", pid.ID())
-	watchers := pid.watchers()
+	logger.Debugf("%s freeing all watcher actors...", pid.Name())
+	pnode, ok := pid.ActorSystem().tree().GetNode(pid.ID())
+	if !ok {
+		pid.logger.Debugf("%s node not found in the actors tree", pid.Name())
+		return nil
+	}
+
+	watchers := pnode.Watchers
 	if watchers.Len() > 0 {
 		eg, ctx := errgroup.WithContext(ctx)
 		for _, watcher := range watchers.Items() {
@@ -1210,95 +1207,104 @@ func (pid *PID) freeWatchers(ctx context.Context) error {
 					ActorId: pid.ID(),
 				}
 
-				if watcher.IsRunning() {
-					logger.Debugf("watcher=(%s) releasing watched=(%s)", watcher.ID(), pid.ID())
-					if err := pid.Tell(ctx, watcher, terminated); err != nil {
-						return err
-					}
-
-					watcher.UnWatch(pid)
-					logger.Debugf("watcher=(%s) released watched=(%s)", watcher.ID(), pid.ID())
+				wid := watcher.GetValue()
+				if wid.IsRunning() {
+					logger.Debugf("watcher=(%s) releasing watched=(%s)", wid.Name(), pid.Name())
+					// ignore error here because the watcher is running
+					_ = pid.Tell(ctx, wid, terminated)
+					wid.UnWatch(pid)
+					logger.Debugf("watcher=(%s) released watched=(%s)", wid.Name(), pid.Name())
 				}
 				return nil
 			})
 		}
 		if err := eg.Wait(); err != nil {
-			logger.Errorf("watcher=(%s) failed to free all watcher error: %v", pid.ID(), err)
+			logger.Errorf("watcher=(%s) failed to free all watcher error: %v", pid.Name(), err)
 			return err
 		}
-		logger.Debugf("%s successfully frees all watcher actors...", pid.ID())
+		logger.Debugf("%s successfully frees all watcher actors...", pid.Name())
 		return nil
 	}
-	logger.Debugf("%s does not have any watcher actors", pid.ID())
+	logger.Debugf("%s does not have any watcher actors", pid.Name())
 	return nil
 }
 
 // freeWatchees releases all actors that have been watched by this actor
-func (pid *PID) freeWatchees(ctx context.Context) error {
+func (pid *PID) freeWatchees() error {
 	logger := pid.logger
-	logger.Debugf("%s freeing all watched actors...", pid.ID())
-	size := pid.watcheesMap.Size()
+	logger.Debugf("%s freeing all watched actors...", pid.Name())
+	pnode, ok := pid.ActorSystem().tree().GetNode(pid.ID())
+	if !ok {
+		pid.logger.Debugf("%s node not found in the actors tree", pid.Name())
+		return nil
+	}
+
+	size := pnode.Watchees.Len()
 	if size > 0 {
-		eg, ctx := errgroup.WithContext(ctx)
-		for _, watched := range pid.watcheesMap.List() {
+		eg := new(errgroup.Group)
+		for _, watched := range pnode.Watchees.Items() {
 			watched := watched
+			wid := watched.GetValue()
 			eg.Go(func() error {
-				logger.Debugf("watcher=(%s) unwatching actor=(%s)", pid.ID(), watched.ID())
-				pid.UnWatch(watched)
-				if err := watched.Shutdown(ctx); err != nil {
-					errwrap := fmt.Errorf(
-						"watcher=(%s) failed to unwatch actor=(%s): %w",
-						pid.ID(), watched.ID(), err,
-					)
-					return errwrap
-				}
-				logger.Debugf("watcher=(%s) successfully unwatch actor=(%s)", pid.ID(), watched.ID())
+				logger.Debugf("watcher=(%s) unwatching actor=(%s)", pid.Name(), wid.Name())
+				pid.UnWatch(wid)
+				logger.Debugf("watcher=(%s) successfully unwatch actor=(%s)", pid.Name(), wid.Name())
 				return nil
 			})
 		}
 		if err := eg.Wait(); err != nil {
-			logger.Errorf("watcher=(%s) failed to unwatch actors: %v", pid.ID(), err)
+			logger.Errorf("watcher=(%s) failed to unwatch actors: %v", pid.Name(), err)
 			return err
 		}
-		logger.Debugf("%s successfully unwatch all watched actors...", pid.ID())
+		logger.Debugf("%s successfully unwatch all watched actors...", pid.Name())
 		return nil
 	}
-	logger.Debugf("%s does not have any watched actors", pid.ID())
+	logger.Debugf("%s does not have any watched actors", pid.Name())
 	return nil
 }
 
 // freeChildren releases all child actors
 func (pid *PID) freeChildren(ctx context.Context) error {
 	logger := pid.logger
-	logger.Debugf("%s freeing all child actors...", pid.ID())
-	size := pid.childrenMap.Size()
-	if size > 0 {
+	logger.Debugf("%s freeing all descendant actors...", pid.Name())
+
+	tree := pid.ActorSystem().tree()
+	pnode, ok := tree.GetNode(pid.ID())
+	if !ok {
+		pid.logger.Debugf("%s node not found in the actors tree", pid.Name())
+		return nil
+	}
+
+	if descendants, ok := tree.Descendants(pid); ok {
 		eg, ctx := errgroup.WithContext(ctx)
-		for _, child := range pid.Children() {
-			child := child
+		for index, descendant := range descendants {
+			descendant := descendant
+			child := descendant.GetValue()
+			index := index
 			eg.Go(func() error {
-				logger.Debugf("parent=(%s) disowning child=(%s)", pid.ID(), child.ID())
+				logger.Debugf("parent=(%s) disowning descendant=(%s)", pid.Name(), child.Name())
+
 				pid.UnWatch(child)
-				pid.childrenMap.Remove(child.Address())
+				pnode.Descendants.Delete(index)
+
 				if err := child.Shutdown(ctx); err != nil {
 					errwrap := fmt.Errorf(
-						"parent=(%s) failed to disown child=(%s): %w", pid.ID(), child.ID(),
+						"parent=(%s) failed to disown descendant=(%s): %w", pid.Name(), child.Name(),
 						err,
 					)
 					return errwrap
 				}
-				logger.Debugf("parent=(%s) successfully disown child=(%s)", pid.ID(), child.ID())
+				logger.Debugf("parent=(%s) successfully disown descendant=(%s)", pid.Name(), child.Name())
 				return nil
 			})
 		}
 		if err := eg.Wait(); err != nil {
-			logger.Errorf("parent=(%s) failed to free all child actors: %v", pid.ID(), err)
+			logger.Errorf("parent=(%s) failed to free all descendant actors: %v", pid.Name(), err)
 			return err
 		}
-		logger.Debugf("%s successfully free all child actors...", pid.ID())
-		return nil
+		logger.Debugf("%s successfully free all descendant actors...", pid.Name())
 	}
-	pid.logger.Debugf("%s does not have any children", pid.ID())
+	pid.logger.Debugf("%s does not have any children", pid.Name())
 	return nil
 }
 
@@ -1331,16 +1337,16 @@ func (pid *PID) passivationLoop() {
 	ticker.Stop()
 
 	if pid.stopping.Load() {
-		pid.logger.Infof("Actor=%s is stopping. No need to passivate", pid.Address().String())
+		pid.logger.Infof("Actor=%s is stopping. No need to passivate", pid.Name())
 		return
 	}
 
-	pid.logger.Infof("Passivation mode has been triggered for actor=%s...", pid.Address().String())
+	pid.logger.Infof("Passivation mode has been triggered for actor=%s...", pid.Name())
 
 	ctx := context.Background()
 	if err := pid.doStop(ctx); err != nil {
 		// TODO: rethink properly about PostStop error handling
-		pid.logger.Errorf("failed to passivate actor=(%s): reason=(%v)", pid.Address().String(), err)
+		pid.logger.Errorf("failed to passivate actor=(%s): reason=(%v)", pid.Name(), err)
 		return
 	}
 
@@ -1352,7 +1358,7 @@ func (pid *PID) passivationLoop() {
 		pid.eventsStream.Publish(eventsTopic, event)
 	}
 
-	pid.logger.Infof("Actor=%s successfully passivated", pid.Address().String())
+	pid.logger.Infof("Actor=%s successfully passivated", pid.Name())
 }
 
 // setBehavior is a utility function that helps set the actor behavior
@@ -1390,44 +1396,35 @@ func (pid *PID) doStop(ctx context.Context) error {
 	// TODO: just signal stash processing done and ignore the messages or process them
 	if pid.stashBox != nil {
 		if err := pid.unstashAll(); err != nil {
-			pid.logger.Errorf("actor=(%s) failed to unstash messages", pid.Address().String())
+			pid.logger.Errorf("actor=(%s) failed to unstash messages", pid.Name())
 			pid.started.Store(false)
 			return err
 		}
 	}
 
-	// wait for all messages in the mailbox to be processed
-	// init a ticker that run every 10 ms to make sure we process all messages in the
-	// mailbox within a second
-	// TODO: revisit this timeout or discard all remaining messages in the mailbox
-	ticker := time.NewTicker(10 * time.Millisecond)
-	tickerStopSig := make(chan types.Unit)
-	go func() {
-		for {
-			select {
-			case <-ticker.C:
-				if pid.mailbox.IsEmpty() {
-					close(tickerStopSig)
-					return
-				}
-			case <-time.After(2 * time.Second):
-				close(tickerStopSig)
-				return
-			}
-		}
-	}()
+	// stop processing messages
+	pid.supervisionStopSignal <- types.Unit{}
+	pid.receiveStopSignal <- types.Unit{}
+
+	// TODO: revisit this part of the code
+	// move remaining messages in the mailbox to deadletter queue
+	// any subscription to the actor system can handle them.
+	// if pid.mailbox.Len() > 0 {
+	// 	pid.logger.Debugf("actor=(%s) mailbox is not empty. remaining messages will be sent to the deadletter queue", pid.Address().String())
+	// 	for !pid.mailbox.IsEmpty() {
+	// 		if dequeued := pid.mailbox.Dequeue(); dequeued != nil {
+	// 			pid.toDeadletterQueue(dequeued, ErrUnhandled)
+	// 		}
+	// 	}
+	// }
 
-	<-tickerStopSig
 	if pid.remoting != nil {
 		pid.remoting.Close()
 	}
 
-	pid.supervisionStopSignal <- types.Unit{}
-	pid.receiveStopSignal <- types.Unit{}
-
 	if err := errorschain.
 		New(errorschain.ReturnFirst()).
-		AddError(pid.freeWatchees(ctx)).
+		AddError(pid.freeWatchees()).
 		AddError(pid.freeChildren(ctx)).
 		AddError(pid.freeWatchers(ctx)).
 		Error(); err != nil {
@@ -1437,18 +1434,11 @@ func (pid *PID) doStop(ctx context.Context) error {
 	}
 
 	pid.started.Store(false)
-	pid.logger.Infof("post shutdown process is on going for actor=%s...", pid.Address().String())
+	pid.logger.Infof("post shutdown process is on going for actor=%s...", pid.Name())
 	pid.reset()
 	return pid.actor.PostStop(ctx)
 }
 
-// setParent set the actor parent.
-func (pid *PID) setParent(parent *PID) {
-	pid.fieldsLocker.Lock()
-	pid.parent = parent
-	pid.fieldsLocker.Unlock()
-}
-
 // supervisionLoop send error to watchers
 func (pid *PID) supervisionLoop() {
 	go func() {
@@ -1468,9 +1458,9 @@ func (pid *PID) notifyParent(err error) {
 	if err == nil || errors.Is(err, ErrDead) {
 		return
 	}
-	// send a message to the parent
-	if pid.parent != nil {
-		_ = pid.Tell(context.Background(), pid.parent, &internalpb.HandleFault{
+
+	if parent := pid.Parent(); parent != nil && !parent.Equals(NoSender) {
+		_ = pid.Tell(context.Background(), parent, &internalpb.HandleFault{
 			ActorId: pid.ID(),
 			Message: err.Error(),
 		})
@@ -1543,7 +1533,7 @@ func (pid *PID) handleCompletion(ctx context.Context, completion *taskCompletion
 	// make sure that the receiver is still alive
 	to := completion.Receiver
 	if !to.IsRunning() {
-		pid.logger.Errorf("unable to pipe message to actor=(%s): not started", to.Address().String())
+		pid.logger.Errorf("unable to pipe message to actor=(%s): not started", to.Name())
 		return
 	}
 
@@ -1553,21 +1543,25 @@ func (pid *PID) handleCompletion(ctx context.Context, completion *taskCompletion
 
 // handleFaultyChild watches for child actor's failure and act based upon the supervisory strategy
 func (pid *PID) handleFaultyChild(msg *internalpb.HandleFault) {
-	for _, cid := range pid.childrenMap.List() {
-		if cid.ID() == msg.GetActorId() {
-			message := msg.GetMessage()
-			pid.logger.Errorf("child actor=(%s) is failing: Err=%s", cid.ID(), message)
-			switch directive := cid.supervisorDirective.(type) {
-			case *StopDirective:
-				pid.handleStopDirective(cid)
-			case *RestartDirective:
-				pid.handleRestartDirective(cid, directive.MaxNumRetries(), directive.Timeout())
-			case *ResumeDirective:
-				// pass
-			default:
-				pid.handleStopDirective(cid)
+	tree := pid.ActorSystem().tree()
+	if descendants, ok := tree.Descendants(pid); ok {
+		for _, descendant := range descendants {
+			cid := descendant.GetValue()
+			if cid.ID() == msg.GetActorId() {
+				message := msg.GetMessage()
+				pid.logger.Errorf("child actor=(%s) is failing: Err=%s", cid.Name(), message)
+				switch directive := cid.supervisorDirective.(type) {
+				case *StopDirective:
+					pid.handleStopDirective(cid)
+				case *RestartDirective:
+					pid.handleRestartDirective(cid, directive.MaxNumRetries(), directive.Timeout())
+				case *ResumeDirective:
+					// pass
+				default:
+					pid.handleStopDirective(cid)
+				}
+				return
 			}
-			return
 		}
 	}
 }
@@ -1575,18 +1569,21 @@ func (pid *PID) handleFaultyChild(msg *internalpb.HandleFault) {
 // handleStopDirective handles the Supervisor stop directive
 func (pid *PID) handleStopDirective(cid *PID) {
 	pid.UnWatch(cid)
-	pid.childrenMap.Remove(cid.Address())
+	tree := pid.ActorSystem().tree()
 	if err := cid.Shutdown(context.Background()); err != nil {
 		// this can enter into some infinite loop if we panic
 		// since we are just shutting down the actor we can just log the error
 		// TODO: rethink properly about PostStop error handling
 		pid.logger.Error(err)
 	}
+
+	tree.DeleteNode(cid)
 }
 
 // handleRestartDirective handles the Supervisor restart directive
 func (pid *PID) handleRestartDirective(cid *PID, maxRetries uint32, timeout time.Duration) {
 	pid.UnWatch(cid)
+
 	ctx := context.Background()
 	var err error
 	if maxRetries == 0 || timeout <= 0 {
@@ -1599,14 +1596,11 @@ func (pid *PID) handleRestartDirective(cid *PID, maxRetries uint32, timeout time
 
 	if err != nil {
 		pid.logger.Error(err)
-		// remove the actor in case it is a child and stop it
-		pid.childrenMap.Remove(cid.Address())
 		if err := cid.Shutdown(ctx); err != nil {
 			pid.logger.Error(err)
 		}
 		return
 	}
-	pid.Watch(cid)
 }
 
 // childAddress returns the address of the given child actor provided the name
diff --git a/actors/pid_node.go b/actors/pid_node.go
new file mode 100644
index 0000000..be1cf2a
--- /dev/null
+++ b/actors/pid_node.go
@@ -0,0 +1,68 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022-2024  Arsene Tochemey Gandote
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package actors
+
+import (
+	"sync/atomic"
+
+	"github.com/tochemey/goakt/v2/internal/slice"
+)
+
+// pidValue represents the data stored in each
+// node of the actors Tree
+type pidValue struct {
+	data *PID
+}
+
+// newPidValue creates an instance of pidValue
+func newPidValue(data *PID) *pidValue {
+	return &pidValue{data: data}
+}
+
+// Value returns the actual pidValue value
+func (v *pidValue) Value() *PID {
+	return v.data
+}
+
+// pidNode represents a single actor node
+// in the actors Tree
+type pidNode struct {
+	ID          string
+	value       atomic.Pointer[pidValue]
+	Descendants *slice.ThreadSafe[*pidNode]
+	Watchers    *slice.ThreadSafe[*pidNode]
+	Watchees    *slice.ThreadSafe[*pidNode]
+}
+
+// SetValue sets a node value
+func (x *pidNode) SetValue(v *pidValue) {
+	x.value.Store(v)
+}
+
+// GetValue returns the underlying value of the node
+func (x *pidNode) GetValue() *PID {
+	v := x.value.Load()
+	return v.Value()
+}
diff --git a/actors/pid_option.go b/actors/pid_option.go
index 792c1e9..71f72f2 100644
--- a/actors/pid_option.go
+++ b/actors/pid_option.go
@@ -111,10 +111,3 @@ func withRemoting(remoting *Remoting) pidOption {
 		pid.remoting = remoting
 	}
 }
-
-// withParent sets the parent id
-func withParent(parent *PID) pidOption {
-	return func(pid *PID) {
-		pid.parent = parent
-	}
-}
diff --git a/actors/pid_tree.go b/actors/pid_tree.go
new file mode 100644
index 0000000..b4d6b5e
--- /dev/null
+++ b/actors/pid_tree.go
@@ -0,0 +1,289 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022-2024  Arsene Tochemey Gandote
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package actors
+
+import (
+	"fmt"
+	"sync"
+	"sync/atomic"
+
+	"github.com/tochemey/goakt/v2/internal/slice"
+)
+
+// pidTree represents the entire actors Tree structure
+type pidTree struct {
+	nodes     *shardedMap
+	parents   *shardedMap
+	nodePool  *sync.Pool
+	valuePool *sync.Pool
+	size      atomic.Int64
+}
+
+// newTree creates a new instance of the actors Tree
+func newTree() *pidTree {
+	return &pidTree{
+		nodes:   newShardedMap(),
+		parents: newShardedMap(),
+		nodePool: &sync.Pool{
+			New: func() any {
+				return &pidNode{
+					Descendants: slice.NewThreadSafe[*pidNode](),
+					Watchees:    slice.NewThreadSafe[*pidNode](),
+					Watchers:    slice.NewThreadSafe[*pidNode](),
+				}
+			},
+		},
+		valuePool: &sync.Pool{
+			New: func() any {
+				return &pidValue{}
+			},
+		},
+	}
+}
+
+// AddNode adds a new node to the tree under a given parent
+func (t *pidTree) AddNode(parent, child *PID) error {
+	var (
+		parentNode *pidNode
+		ok         bool
+	)
+	// validate parent node existence
+	if !parent.Equals(NoSender) {
+		parentNode, ok = t.getNode(parent.ID())
+		if !ok || parentNode == nil {
+			return fmt.Errorf("parent node=(%s) does not exist", parent.ID())
+		}
+	}
+
+	// create a new node from the pool
+	newNode := t.nodePool.Get().(*pidNode)
+	newNode.ID = child.ID()
+	newNode.Descendants.Reset()
+	newNode.Watchers.Reset()
+	newNode.Watchees.Reset()
+
+	// create a pidValue using the pool and set its data
+	val := t.valuePool.Get().(*pidValue)
+	val.data = child
+
+	// store the value atomically in the node
+	newNode.SetValue(val)
+
+	// store the node in the tree
+	t.nodes.Store(child.ID(), newNode)
+
+	// when parentNode is defined
+	if parentNode != nil {
+		t.addChild(parentNode, newNode)
+		t.updateAncestors(parent.ID(), child.ID())
+	}
+
+	t.size.Add(1)
+	return nil
+}
+
+// AddWatcher adds a watcher to the given node. Make sure to check the existence of both PID
+// before watching because this call will do nothing when the watcher and the watched node do not exist in
+// the tree
+func (t *pidTree) AddWatcher(node, watcher *PID) {
+	currentNode, ok := t.getNode(node.ID())
+	if !ok || currentNode == nil {
+		return
+	}
+
+	watcherNode, ok := t.getNode(watcher.ID())
+	if !ok {
+		return
+	}
+
+	watcherNode.Watchees.Append(currentNode)
+	currentNode.Watchers.Append(watcherNode)
+}
+
+// Ancestors retrieves all ancestors nodes of a given node
+func (t *pidTree) Ancestors(pid *PID) ([]*pidNode, bool) {
+	ancestorIDs, ok := t.getAncestors(pid.ID())
+	if !ok {
+		return nil, false
+	}
+
+	var ancestors []*pidNode
+	for _, ancestorID := range ancestorIDs {
+		if ancestor, ok := t.getNode(ancestorID); ok {
+			ancestors = append(ancestors, ancestor)
+		}
+	}
+	return ancestors, true
+}
+
+// Parent returns a given PID direct parent
+func (t *pidTree) Parent(pid *PID) (*pidNode, bool) {
+	ancestors, ok := t.getAncestors(pid.ID())
+	if ok && len(ancestors) > 0 {
+		return t.getNode(ancestors[0])
+	}
+	return nil, false
+}
+
+// GrandParent retrieves the grandparent of a node
+func (t *pidTree) GrandParent(pid *PID) (*pidNode, bool) {
+	ancestors, ok := t.getAncestors(pid.ID())
+	if ok && len(ancestors) > 1 {
+		return t.getNode(ancestors[1])
+	}
+	return nil, false
+}
+
+// GreatGrandParent retrieves the great-grand-parent of a node
+func (t *pidTree) GreatGrandParent(pid *PID) (*pidNode, bool) {
+	ancestors, ok := t.getAncestors(pid.ID())
+	if ok && len(ancestors) > 2 {
+		return t.getNode(ancestors[2])
+	}
+	return nil, false
+}
+
+// Descendants retrieves all descendants of the node with the given ID.
+func (t *pidTree) Descendants(pid *PID) ([]*pidNode, bool) {
+	node, ok := t.GetNode(pid.ID())
+	if !ok {
+		return nil, false
+	}
+
+	var descendants []*pidNode
+	var collectDescendants func(n *pidNode)
+	collectDescendants = func(n *pidNode) {
+		for _, child := range n.Descendants.Items() {
+			descendants = append(descendants, child)
+			collectDescendants(child) // recurse through the children
+		}
+	}
+
+	collectDescendants(node)
+	return descendants, true
+}
+
+// DeleteNode deletes a node and all its descendants
+func (t *pidTree) DeleteNode(pid *PID) {
+	node, ok := t.getNode(pid.ID())
+	if !ok {
+		return
+	}
+
+	// remove the node from its parent's Children slice
+	if ancestors, ok := t.parents.Load(pid.ID()); ok && len(ancestors.([]string)) > 0 {
+		parentID := ancestors.([]string)[0]
+		if parent, found := t.GetNode(parentID); found {
+			parent.Descendants = filterOutChild(parent.Descendants, pid.ID())
+		}
+	}
+
+	// recursive function to delete a node and its descendants
+	var deleteChildren func(n *pidNode)
+	deleteChildren = func(n *pidNode) {
+		for index, child := range n.Descendants.Items() {
+			n.Descendants.Delete(index)
+			deleteChildren(child)
+		}
+		// delete node from maps and pool
+		t.nodes.Delete(n.ID)
+		t.parents.Delete(n.ID)
+		t.nodePool.Put(n)
+		t.size.Add(-1)
+	}
+
+	deleteChildren(node)
+}
+
+// GetNode retrieves a node by its ID
+func (t *pidTree) GetNode(id string) (*pidNode, bool) {
+	return t.getNode(id)
+}
+
+// Nodes retrieves all nodes in the tree efficiently
+func (t *pidTree) Nodes() []*pidNode {
+	var nodes []*pidNode
+	t.nodes.Range(func(_, value any) bool {
+		node := value.(*pidNode)
+		nodes = append(nodes, node)
+		return true
+	})
+	return nodes
+}
+
+// Size returns the current number of nodes in the tree
+func (t *pidTree) Size() int64 {
+	return t.size.Load()
+}
+
+// Reset clears all nodes and parents, resetting the tree to an empty state
+func (t *pidTree) Reset() {
+	t.nodes.Reset()   // Reset nodes map
+	t.parents.Reset() // Reset parents map
+	t.size.Store(0)
+}
+
+// getNode is a helper to get a node from sync.Map
+func (t *pidTree) getNode(id string) (*pidNode, bool) {
+	if value, ok := t.nodes.Load(id); ok {
+		return value.(*pidNode), true
+	}
+	return nil, false
+}
+
+// getAncestors returns the list of ancestor nodes
+func (t *pidTree) getAncestors(id string) ([]string, bool) {
+	if value, ok := t.parents.Load(id); ok {
+		return value.([]string), true
+	}
+	return nil, false
+}
+
+// addChild safely appends a child to a parent's Children slice using atomic operations.
+func (t *pidTree) addChild(parent *pidNode, child *pidNode) {
+	parent.Descendants.Append(child)
+	parent.Watchees.Append(child)
+	child.Watchers.Append(parent)
+}
+
+// updateAncestors updates the parent/ancestor relationships.
+func (t *pidTree) updateAncestors(parentID, childID string) {
+	if ancestors, ok := t.getAncestors(parentID); ok {
+		t.parents.Store(childID, append([]string{parentID}, ancestors...))
+	} else {
+		t.parents.Store(childID, []string{parentID})
+	}
+}
+
+// filterOutChild removes the node with the given ID from the Children slice.
+func filterOutChild(children *slice.ThreadSafe[*pidNode], childID string) *slice.ThreadSafe[*pidNode] {
+	for i, child := range children.Items() {
+		if child.ID == childID {
+			children.Delete(i)
+			return children
+		}
+	}
+	return children
+}
diff --git a/actors/receive_context.go b/actors/receive_context.go
index 53713e2..c9d2753 100644
--- a/actors/receive_context.go
+++ b/actors/receive_context.go
@@ -413,13 +413,6 @@ func (rctx *ReceiveContext) PipeTo(to *PID, task future.Task) {
 	}
 }
 
-// Parent returns the parent of the given actor
-// in case the receiving actor is a child actor
-// this is just a convenient method
-func (rctx *ReceiveContext) Parent() *PID {
-	return rctx.self.Parent()
-}
-
 // Logger returns the logger used in the actor system
 func (rctx *ReceiveContext) Logger() log.Logger {
 	return rctx.self.Logger()
diff --git a/actors/remoting.go b/actors/remoting.go
index 6ab8f37..b6b23c0 100644
--- a/actors/remoting.go
+++ b/actors/remoting.go
@@ -68,7 +68,7 @@ func (r *Remoting) RemoteTell(ctx context.Context, from, to *address.Address, me
 		return ErrInvalidMessage(err)
 	}
 
-	remoteClient := r.Client(to.GetHost(), int(to.GetPort()))
+	remoteClient := r.serviceClient(to.GetHost(), int(to.GetPort()))
 	request := &internalpb.RemoteTellRequest{
 		RemoteMessage: &internalpb.RemoteMessage{
 			Sender:   from.Address,
@@ -103,7 +103,7 @@ func (r *Remoting) RemoteAsk(ctx context.Context, from, to *address.Address, mes
 		return nil, ErrInvalidMessage(err)
 	}
 
-	remoteClient := r.Client(to.GetHost(), int(to.GetPort()))
+	remoteClient := r.serviceClient(to.GetHost(), int(to.GetPort()))
 	request := &internalpb.RemoteAskRequest{
 		RemoteMessage: &internalpb.RemoteMessage{
 			Sender:   from.Address,
@@ -151,7 +151,7 @@ func (r *Remoting) RemoteAsk(ctx context.Context, from, to *address.Address, mes
 
 // RemoteLookup look for an actor address on a remote node.
 func (r *Remoting) RemoteLookup(ctx context.Context, host string, port int, name string) (addr *address.Address, err error) {
-	remoteClient := r.Client(host, port)
+	remoteClient := r.serviceClient(host, port)
 	request := connect.NewRequest(
 		&internalpb.RemoteLookupRequest{
 			Host: host,
@@ -192,7 +192,7 @@ func (r *Remoting) RemoteBatchTell(ctx context.Context, from, to *address.Addres
 		)
 	}
 
-	remoteClient := r.Client(to.GetHost(), int(to.GetPort()))
+	remoteClient := r.serviceClient(to.GetHost(), int(to.GetPort()))
 	stream := remoteClient.RemoteTell(ctx)
 	for _, request := range requests {
 		err := stream.Send(request)
@@ -237,7 +237,7 @@ func (r *Remoting) RemoteBatchAsk(ctx context.Context, from, to *address.Address
 		)
 	}
 
-	remoteClient := r.Client(to.GetHost(), int(to.GetPort()))
+	remoteClient := r.serviceClient(to.GetHost(), int(to.GetPort()))
 	stream := remoteClient.RemoteAsk(ctx)
 	errc := make(chan error, 1)
 
@@ -279,7 +279,7 @@ func (r *Remoting) RemoteBatchAsk(ctx context.Context, from, to *address.Address
 
 // RemoteSpawn creates an actor on a remote node. The given actor needs to be registered on the remote node using the Register method of ActorSystem
 func (r *Remoting) RemoteSpawn(ctx context.Context, host string, port int, name, actorType string) error {
-	remoteClient := r.Client(host, port)
+	remoteClient := r.serviceClient(host, port)
 	request := connect.NewRequest(
 		&internalpb.RemoteSpawnRequest{
 			Host:      host,
@@ -306,7 +306,7 @@ func (r *Remoting) RemoteSpawn(ctx context.Context, host string, port int, name,
 
 // RemoteReSpawn restarts actor on a remote node.
 func (r *Remoting) RemoteReSpawn(ctx context.Context, host string, port int, name string) error {
-	remoteClient := r.Client(host, port)
+	remoteClient := r.serviceClient(host, port)
 	request := connect.NewRequest(
 		&internalpb.RemoteReSpawnRequest{
 			Host: host,
@@ -328,7 +328,7 @@ func (r *Remoting) RemoteReSpawn(ctx context.Context, host string, port int, nam
 
 // RemoteStop stops an actor on a remote node.
 func (r *Remoting) RemoteStop(ctx context.Context, host string, port int, name string) error {
-	remoteClient := r.Client(host, port)
+	remoteClient := r.serviceClient(host, port)
 	request := connect.NewRequest(
 		&internalpb.RemoteStopRequest{
 			Host: host,
@@ -348,13 +348,13 @@ func (r *Remoting) RemoteStop(ctx context.Context, host string, port int, name s
 	return nil
 }
 
-// Close closes the Client connection
+// Close closes the serviceClient connection
 func (r *Remoting) Close() {
 	r.client.CloseIdleConnections()
 }
 
-// Client returns a Remoting service client instance
-func (r *Remoting) Client(host string, port int) internalpbconnect.RemotingServiceClient {
+// serviceClient returns a Remoting service client instance
+func (r *Remoting) serviceClient(host string, port int) internalpbconnect.RemotingServiceClient {
 	endpoint := http.URL(host, port)
 	return internalpbconnect.NewRemotingServiceClient(r.client, endpoint)
 }
diff --git a/actors/sharded_map.go b/actors/sharded_map.go
new file mode 100644
index 0000000..a943add
--- /dev/null
+++ b/actors/sharded_map.go
@@ -0,0 +1,92 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022-2024  Arsene Tochemey Gandote
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package actors
+
+import (
+	"hash/fnv"
+	"sync"
+)
+
+const numShards = 64
+
+// shardedMap is a concurrent map with sharding for scalability
+type shardedMap struct {
+	shards []*sync.Map
+}
+
+// newShardedMap creates an instance of shardedMap
+func newShardedMap() *shardedMap {
+	shards := make([]*sync.Map, numShards)
+	for i := range shards {
+		shards[i] = &sync.Map{}
+	}
+	return &shardedMap{
+		shards: shards,
+	}
+}
+
+func (s *shardedMap) getShard(key string) *sync.Map {
+	hash := fnv64(key) % numShards
+	return s.shards[hash]
+}
+
+func (s *shardedMap) Load(key string) (any, bool) {
+	shard := s.getShard(key)
+	return shard.Load(key)
+}
+
+func (s *shardedMap) Store(key string, value any) {
+	shard := s.getShard(key)
+	shard.Store(key, value)
+}
+
+func (s *shardedMap) Delete(key string) {
+	shard := s.getShard(key)
+	shard.Delete(key)
+}
+
+func (s *shardedMap) Range(f func(key, value any) bool) {
+	for i := 0; i < numShards; i++ {
+		shard := s.shards[i]
+		shard.Range(f)
+	}
+}
+
+func (s *shardedMap) Reset() {
+	// Reset each shard's map
+	for i := 0; i < numShards; i++ {
+		shard := s.shards[i]
+		shard.Range(func(key, _ any) bool {
+			shard.Delete(key) // Clear the entry
+			return true
+		})
+	}
+}
+
+func fnv64(key string) uint64 {
+	hash := fnv.New64()
+	_, _ = hash.Write([]byte(key))
+	return hash.Sum64()
+}
diff --git a/internal/lib/lib.go b/internal/lib/lib.go
index 601fe29..4930ba4 100644
--- a/internal/lib/lib.go
+++ b/internal/lib/lib.go
@@ -25,6 +25,8 @@
 package lib
 
 import (
+	"log"
+	"runtime"
 	"time"
 
 	"github.com/tochemey/goakt/v2/internal/types"
@@ -39,3 +41,10 @@ func Pause(duration time.Duration) {
 	<-stopCh
 	timer.Stop()
 }
+
+// Debug is used this to detect if a goroutine is stuck
+func Debug() {
+	buf := make([]byte, 1<<20)
+	runtime.Stack(buf, true)
+	log.Printf("%s", buf)
+}
diff --git a/internal/slice/lock_free.go b/internal/slice/lock_free.go
deleted file mode 100644
index fd8d33d..0000000
--- a/internal/slice/lock_free.go
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * MIT License
- *
- * Copyright (c) 2022-2024  Arsene Tochemey Gandote
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package slice
-
-import (
-	"sync/atomic"
-	"unsafe"
-)
-
-type header[T any] struct {
-	data  []T
-	count uint64
-}
-
-// LockFree type that can be safely shared between goroutines.
-type LockFree[T any] struct {
-	head unsafe.Pointer
-}
-
-// NewLockFree creates a new lock-free thread-safe slice.
-func NewLockFree[T any]() *LockFree[T] {
-	return &LockFree[T]{
-		head: unsafe.Pointer(&header[T]{
-			data:  make([]T, 0),
-			count: 0,
-		}),
-	}
-}
-
-// Len returns the number of items
-func (cs *LockFree[T]) Len() int {
-	head := (*header[T])(atomic.LoadPointer(&cs.head))
-	return int(atomic.LoadUint64(&head.count))
-}
-
-// Append adds an item to the concurrent slice.
-func (cs *LockFree[T]) Append(item T) {
-	for {
-		currentHead := (*header[T])(atomic.LoadPointer(&cs.head))
-		newData := append(currentHead.data, item)
-		newCount := atomic.AddUint64(&currentHead.count, 1)
-		newHead := &header[T]{
-			data:  newData,
-			count: newCount,
-		}
-
-		if atomic.CompareAndSwapPointer(&cs.head, unsafe.Pointer(currentHead), unsafe.Pointer(newHead)) {
-			return
-		}
-	}
-}
-
-// Get returns the slice item at the given index
-func (cs *LockFree[T]) Get(index int) (item T) {
-	data := (*header[T])(atomic.LoadPointer(&cs.head)).data
-	if isSet(data, index) {
-		return data[index]
-	}
-	var xnil T
-	return xnil
-}
-
-// Delete an item from the slice
-func (cs *LockFree[T]) Delete(index int) {
-	for {
-		currentHead := (*header[T])(atomic.LoadPointer(&cs.head))
-		if isSet(currentHead.data, index) {
-			newData := append(currentHead.data[:index], currentHead.data[index+1:]...)
-			newCount := atomic.AddUint64(&currentHead.count, ^uint64(0))
-			newHead := &header[T]{
-				data:  newData,
-				count: newCount,
-			}
-			if atomic.CompareAndSwapPointer(&cs.head, unsafe.Pointer(currentHead), unsafe.Pointer(newHead)) {
-				return
-			}
-		}
-	}
-}
-
-// Items returns the list of items
-func (cs *LockFree[T]) Items() []T {
-	return (*header[T])(atomic.LoadPointer(&cs.head)).data
-}
-
-// Reset resets the slice
-func (cs *LockFree[T]) Reset() {
-	for {
-		currentHead := (*header[T])(atomic.LoadPointer(&cs.head))
-		newHead := unsafe.Pointer(&header[T]{
-			data:  make([]T, 0),
-			count: 0,
-		})
-		if atomic.CompareAndSwapPointer(&cs.head, unsafe.Pointer(currentHead), unsafe.Pointer(newHead)) {
-			return
-		}
-	}
-}
-
-func isSet[T any](arr []T, index int) bool {
-	return len(arr) > index
-}
diff --git a/internal/slice/thread_safe.go b/internal/slice/thread_safe.go
new file mode 100644
index 0000000..f2b4db3
--- /dev/null
+++ b/internal/slice/thread_safe.go
@@ -0,0 +1,94 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022-2024  Arsene Tochemey Gandote
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package slice
+
+import (
+	"sync"
+)
+
+// ThreadSafe type that can be safely shared between goroutines.
+type ThreadSafe[T any] struct {
+	data []T
+	mu   sync.RWMutex
+}
+
+// NewThreadSafe creates a new lock-free thread-safe slice.
+func NewThreadSafe[T any]() *ThreadSafe[T] {
+	return &ThreadSafe[T]{data: []T{}}
+}
+
+// Len returns the number of items
+func (cs *ThreadSafe[T]) Len() int {
+	cs.mu.RLock()
+	l := len(cs.data)
+	cs.mu.RUnlock()
+	return l
+}
+
+// Append adds an item to the concurrent slice.
+func (cs *ThreadSafe[T]) Append(item T) {
+	cs.mu.Lock()
+	cs.data = append(cs.data, item)
+	cs.mu.Unlock()
+}
+
+// Get returns the slice item at the given index
+func (cs *ThreadSafe[T]) Get(index int) (item T) {
+	cs.mu.RLock()
+	if index < 0 || index >= len(cs.data) {
+		var zero T
+		cs.mu.RUnlock()
+		return zero
+	}
+	cs.mu.RUnlock()
+	return cs.data[index]
+}
+
+// Delete an item from the slice
+func (cs *ThreadSafe[T]) Delete(index int) {
+	cs.mu.Lock()
+	if index < 0 || index >= len(cs.data) {
+		cs.mu.Unlock()
+		return
+	}
+	cs.data = append(cs.data[:index], cs.data[index+1:]...)
+	cs.mu.Unlock()
+}
+
+// Items returns the list of items
+func (cs *ThreadSafe[T]) Items() []T {
+	cs.mu.RLock()
+	dataCopy := make([]T, len(cs.data))
+	copy(dataCopy, cs.data)
+	cs.mu.RUnlock()
+	return dataCopy
+}
+
+// Reset resets the slice
+func (cs *ThreadSafe[T]) Reset() {
+	cs.mu.Lock()
+	cs.data = []T{}
+	cs.mu.Unlock()
+}
diff --git a/internal/tcp/tcp.go b/internal/tcp/tcp.go
index 120b238..7471569 100644
--- a/internal/tcp/tcp.go
+++ b/internal/tcp/tcp.go
@@ -24,7 +24,12 @@
 
 package tcp
 
-import "net"
+import (
+	"fmt"
+	"net"
+
+	"github.com/hashicorp/go-sockaddr"
+)
 
 // GetHostPort returns the actual ip address and port from a given address
 func GetHostPort(address string) (string, int, error) {
@@ -36,3 +41,39 @@ func GetHostPort(address string) (string, int, error) {
 
 	return addr.IP.String(), addr.Port, nil
 }
+
+// GetBindIP tries to find an appropriate bindIP to bind and propagate.
+func GetBindIP(address string) (string, error) {
+	bindIP, _, err := GetHostPort(address)
+	if err != nil {
+		return "", fmt.Errorf("invalid address: %w", err)
+	}
+
+	if bindIP == "0.0.0.0" {
+		// if we're not bound to a specific IP, let's use a suitable private IP address.
+		ipStr, err := sockaddr.GetPrivateIP()
+		if err != nil {
+			return "", fmt.Errorf("failed to get private interface addresses: %w", err)
+		}
+
+		// if we could not find a private address, we need to expand our search to a public
+		// ip address
+		if ipStr == "" {
+			ipStr, err = sockaddr.GetPublicIP()
+			if err != nil {
+				return "", fmt.Errorf("failed to get public interface addresses: %w", err)
+			}
+		}
+
+		if ipStr == "" {
+			return "", fmt.Errorf("no private IP address found, and explicit IP not provided")
+		}
+
+		parsed := net.ParseIP(ipStr)
+		if parsed == nil {
+			return "", fmt.Errorf("failed to parse private IP address: %q", ipStr)
+		}
+		bindIP = parsed.String()
+	}
+	return bindIP, nil
+}


Test patch:
diff --git a/actors/actor_system_test.go b/actors/actor_system_test.go
index d34023a..008ed5c 100644
--- a/actors/actor_system_test.go
+++ b/actors/actor_system_test.go
@@ -88,6 +88,8 @@ func TestActorSystem(t *testing.T) {
 		err := sys.Start(ctx)
 		assert.NoError(t, err)
 
+		lib.Pause(time.Second)
+
 		actor := newActor()
 		actorRef, err := sys.Spawn(ctx, "Test", actor)
 		assert.NoError(t, err)
@@ -95,13 +97,8 @@ func TestActorSystem(t *testing.T) {
 
 		// stop the actor after some time
 		lib.Pause(time.Second)
-
-		t.Cleanup(
-			func() {
-				err = sys.Stop(ctx)
-				assert.NoError(t, err)
-			},
-		)
+		err = sys.Stop(ctx)
+		assert.NoError(t, err)
 	})
 	t.Run("With Spawn an actor with invalid actor name", func(t *testing.T) {
 		ctx := context.TODO()
@@ -1147,6 +1144,55 @@ func TestActorSystem(t *testing.T) {
 
 		require.NoError(t, sys.Stop(ctx))
 	})
+	t.Run("With SpawnNamedFromFunc when actor already exist", func(t *testing.T) {
+		ctx := context.TODO()
+		ports := dynaport.Get(1)
+
+		logger := log.DiscardLogger
+		host := "127.0.0.1"
+
+		newActorSystem, err := NewActorSystem(
+			"test",
+			WithPassivationDisabled(),
+			WithLogger(logger),
+			WithJanitorInterval(time.Minute),
+			WithRemoting(host, int32(ports[0])))
+
+		require.NoError(t, err)
+
+		// start the actor system
+		err = newActorSystem.Start(ctx)
+		require.NoError(t, err)
+
+		receiveFn := func(_ context.Context, message proto.Message) error {
+			expected := &testpb.Reply{Content: "test spawn from func"}
+			assert.True(t, proto.Equal(expected, message))
+			return nil
+		}
+
+		actorName := "name"
+		actorRef, err := newActorSystem.SpawnNamedFromFunc(ctx, actorName, receiveFn)
+		assert.NoError(t, err)
+		assert.NotNil(t, actorRef)
+
+		// stop the actor after some time
+		lib.Pause(time.Second)
+
+		// send a message to the actor
+		require.NoError(t, Tell(ctx, actorRef, &testpb.Reply{Content: "test spawn from func"}))
+
+		newInstance, err := newActorSystem.SpawnNamedFromFunc(ctx, actorName, receiveFn)
+		require.NoError(t, err)
+		require.NotNil(t, newInstance)
+		require.True(t, newInstance.Equals(actorRef))
+
+		t.Cleanup(
+			func() {
+				err = newActorSystem.Stop(ctx)
+				assert.NoError(t, err)
+			},
+		)
+	})
 	t.Run("With SpawnFromFunc (cluster/remote enabled)", func(t *testing.T) {
 		ctx := context.TODO()
 		nodePorts := dynaport.Get(3)
diff --git a/actors/helper_test.go b/actors/helper_test.go
index f9a6ddd..857b552 100644
--- a/actors/helper_test.go
+++ b/actors/helper_test.go
@@ -242,13 +242,13 @@ func (e *exchanger) PostStop(context.Context) error {
 
 var _ Actor = &exchanger{}
 
-type stasQA struct{}
+type stashQA struct{}
 
-func (x *stasQA) PreStart(context.Context) error {
+func (x *stashQA) PreStart(context.Context) error {
 	return nil
 }
 
-func (x *stasQA) Receive(ctx *ReceiveContext) {
+func (x *stashQA) Receive(ctx *ReceiveContext) {
 	switch ctx.Message().(type) {
 	case *goaktpb.PostStart:
 	case *testspb.TestStash:
@@ -260,7 +260,7 @@ func (x *stasQA) Receive(ctx *ReceiveContext) {
 	}
 }
 
-func (x *stasQA) Ready(ctx *ReceiveContext) {
+func (x *stashQA) Ready(ctx *ReceiveContext) {
 	switch ctx.Message().(type) {
 	case *goaktpb.PostStart:
 	case *testspb.TestStash:
@@ -276,11 +276,11 @@ func (x *stasQA) Ready(ctx *ReceiveContext) {
 	}
 }
 
-func (x *stasQA) PostStop(context.Context) error {
+func (x *stashQA) PostStop(context.Context) error {
 	return nil
 }
 
-var _ Actor = &stasQA{}
+var _ Actor = &stashQA{}
 
 type preStartQA struct{}
 
@@ -464,6 +464,7 @@ func startClusterSystem(t *testing.T, serverAddr string) (ActorSystem, discovery
 		WithPassivationDisabled(),
 		WithLogger(logger),
 		WithRemoting(host, int32(remotingPort)),
+		WithJanitorInterval(time.Minute),
 		WithPeerStateLoopInterval(500*time.Millisecond),
 		WithCluster(
 			NewClusterConfig().
diff --git a/actors/pid_test.go b/actors/pid_test.go
index 93c1f42..4be8ed6 100644
--- a/actors/pid_test.go
+++ b/actors/pid_test.go
@@ -39,7 +39,6 @@ import (
 
 	"github.com/tochemey/goakt/v2/address"
 	"github.com/tochemey/goakt/v2/goaktpb"
-	"github.com/tochemey/goakt/v2/internal/eventstream"
 	"github.com/tochemey/goakt/v2/internal/lib"
 	"github.com/tochemey/goakt/v2/log"
 	"github.com/tochemey/goakt/v2/test/data/testpb"
@@ -56,20 +55,24 @@ func TestReceive(t *testing.T) {
 	t.Run("With happy path", func(t *testing.T) {
 		ctx := context.TODO()
 		ports := dynaport.Get(1)
-		// create the actor path
-		actorPath := address.New("Test", "sys", "host", ports[0])
+		host := "127.0.0.1"
 
-		// create the actor ref
-		pid, err := newPID(
-			ctx,
-			actorPath,
-			newActor(),
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger))
+		actorSystem, err := NewActorSystem("testSys",
+			WithRemoting(host, int32(ports[0])),
+			WithLogger(log.DiscardLogger))
+		require.NoError(t, err)
+		require.NotNil(t, actorSystem)
+
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
 
+		// create the actor ref
+		pid, err := actorSystem.Spawn(ctx, "name", newActor())
 		require.NoError(t, err)
 		assert.NotNil(t, pid)
-		// let us send 10 public to the actor
+
+		// let us send 10 messages to the actor
 		count := 10
 		for i := 0; i < count; i++ {
 			receiveContext := &ReceiveContext{
@@ -89,22 +92,28 @@ func TestReceive(t *testing.T) {
 		// stop the actor
 		err = pid.Shutdown(ctx)
 		assert.NoError(t, err)
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 }
 func TestPassivation(t *testing.T) {
 	t.Run("With happy path", func(t *testing.T) {
 		ctx := context.TODO()
-		// create a Ping actor
-		opts := []pidOption{
-			withInitMaxRetries(1),
-			withPassivationAfter(passivateAfter),
-		}
-
 		ports := dynaport.Get(1)
-		// create the actor path
-		actorPath := address.New("Test", "sys", "host", ports[0])
+		host := "127.0.0.1"
+
+		actorSystem, err := NewActorSystem("testSys",
+			WithRemoting(host, int32(ports[0])),
+			WithExpireActorAfter(passivateAfter),
+			WithLogger(log.DiscardLogger))
+		require.NoError(t, err)
+		require.NotNil(t, actorSystem)
+
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
 
-		pid, err := newPID(ctx, actorPath, newActor(), opts...)
+		// create the actor path
+		pid, err := actorSystem.Spawn(ctx, "test", newActor())
 		require.NoError(t, err)
 		assert.NotNil(t, pid)
 
@@ -121,20 +130,26 @@ func TestPassivation(t *testing.T) {
 		err = Tell(ctx, pid, new(testpb.TestSend))
 		assert.Error(t, err)
 		assert.EqualError(t, err, ErrDead.Error())
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 	t.Run("With actor shutdown failure", func(t *testing.T) {
 		ctx := context.TODO()
-		// create a Ping actor
-		opts := []pidOption{
-			withInitMaxRetries(1),
-			withPassivationAfter(passivateAfter),
-		}
-
+		host := "127.0.0.1"
 		ports := dynaport.Get(1)
-		// create the actor path
-		actorPath := address.New("Test", "sys", "host", ports[0])
 
-		pid, err := newPID(ctx, actorPath, &postStopQA{}, opts...)
+		actorSystem, err := NewActorSystem("testSys",
+			WithRemoting(host, int32(ports[0])),
+			WithExpireActorAfter(passivateAfter),
+			WithLogger(log.DiscardLogger))
+
+		require.NoError(t, err)
+		require.NotNil(t, actorSystem)
+
+		require.NoError(t, actorSystem.Start(ctx))
+		lib.Pause(time.Second)
+
+		// create the actor path
+		pid, err := actorSystem.Spawn(ctx, "test", &postStopQA{})
 		require.NoError(t, err)
 		assert.NotNil(t, pid)
 
@@ -151,24 +166,26 @@ func TestPassivation(t *testing.T) {
 		err = Tell(ctx, pid, new(testpb.TestSend))
 		assert.Error(t, err)
 		assert.EqualError(t, err, ErrDead.Error())
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 }
 func TestReply(t *testing.T) {
 	t.Run("With happy path", func(t *testing.T) {
 		ctx := context.TODO()
-		// create a Ping actor
-		opts := []pidOption{
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger),
-		}
-
-		// create the actor path
+		host := "127.0.0.1"
 		ports := dynaport.Get(1)
-		// create the actor path
-		actorPath := address.New("Test", "sys", "host", ports[0])
 
-		pid, err := newPID(ctx, actorPath, newActor(), opts...)
+		actorSystem, err := NewActorSystem("testSys",
+			WithRemoting(host, int32(ports[0])),
+			WithLogger(log.DiscardLogger))
 
+		require.NoError(t, err)
+		require.NotNil(t, actorSystem)
+
+		require.NoError(t, actorSystem.Start(ctx))
+		lib.Pause(time.Second)
+
+		pid, err := actorSystem.Spawn(ctx, "test", newActor())
 		require.NoError(t, err)
 		assert.NotNil(t, pid)
 
@@ -180,21 +197,25 @@ func TestReply(t *testing.T) {
 		// stop the actor
 		err = pid.Shutdown(ctx)
 		assert.NoError(t, err)
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 	t.Run("With timeout", func(t *testing.T) {
 		ctx := context.TODO()
-		// create a Ping actor
-		opts := []pidOption{
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger),
-		}
-
-		// create the actor path
+		host := "127.0.0.1"
 		ports := dynaport.Get(1)
-		// create the actor path
-		actorPath := address.New("Test", "sys", "host", ports[0])
-		pid, err := newPID(ctx, actorPath, newActor(), opts...)
 
+		actorSystem, err := NewActorSystem("testSys",
+			WithRemoting(host, int32(ports[0])),
+			WithLogger(log.DiscardLogger))
+
+		require.NoError(t, err)
+		require.NotNil(t, actorSystem)
+
+		require.NoError(t, actorSystem.Start(ctx))
+		lib.Pause(time.Second)
+
+		// create the actor path
+		pid, err := actorSystem.Spawn(ctx, "test", newActor())
 		require.NoError(t, err)
 		assert.NotNil(t, pid)
 
@@ -205,21 +226,26 @@ func TestReply(t *testing.T) {
 		// stop the actor
 		err = pid.Shutdown(ctx)
 		assert.NoError(t, err)
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 	t.Run("With actor not ready", func(t *testing.T) {
 		ctx := context.TODO()
-		// create a Ping actor
-		opts := []pidOption{
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger),
-		}
-
-		// create the actor path
+		host := "127.0.0.1"
 		ports := dynaport.Get(1)
-		// create the actor path
-		actorPath := address.New("Test", "sys", "host", ports[0])
-		pid, err := newPID(ctx, actorPath, newActor(), opts...)
 
+		actorSystem, err := NewActorSystem("testSys",
+			WithRemoting(host, int32(ports[0])),
+			WithLogger(log.DiscardLogger))
+
+		require.NoError(t, err)
+		require.NotNil(t, actorSystem)
+
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
+
+		// create the actor path
+		pid, err := actorSystem.Spawn(ctx, "test", newActor())
 		require.NoError(t, err)
 		assert.NotNil(t, pid)
 
@@ -231,25 +257,28 @@ func TestReply(t *testing.T) {
 		assert.Error(t, err)
 		assert.EqualError(t, err, ErrDead.Error())
 		assert.Nil(t, actual)
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 }
 func TestRestart(t *testing.T) {
 	t.Run("With restart a stopped actor", func(t *testing.T) {
 		ctx := context.TODO()
+		host := "127.0.0.1"
+		ports := dynaport.Get(1)
 
-		// create a Ping actor
-		actor := newActor()
-		assert.NotNil(t, actor)
+		actorSystem, err := NewActorSystem("testSys",
+			WithRemoting(host, int32(ports[0])),
+			WithExpireActorAfter(10*time.Second),
+			WithLogger(log.DiscardLogger))
 
-		// create the actor path
-		ports := dynaport.Get(1)
-		// create the actor path
-		actorPath := address.New("Test", "sys", "host", ports[0])
-		// create the actor ref
-		pid, err := newPID(ctx, actorPath, actor,
-			withInitMaxRetries(1),
-			withPassivationAfter(10*time.Second),
-			withCustomLogger(log.DiscardLogger))
+		require.NoError(t, err)
+		require.NotNil(t, actorSystem)
+
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
+
+		pid, err := actorSystem.Spawn(ctx, "test", newActor())
 
 		require.NoError(t, err)
 		assert.NotNil(t, pid)
@@ -279,22 +308,25 @@ func TestRestart(t *testing.T) {
 		// stop the actor
 		err = pid.Shutdown(ctx)
 		assert.NoError(t, err)
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 	t.Run("With restart an actor", func(t *testing.T) {
 		ctx := context.TODO()
-
-		// create a Ping actor
-		actor := newActor()
-		assert.NotNil(t, actor)
-		// create the actor path
+		host := "127.0.0.1"
 		ports := dynaport.Get(1)
-		// create the actor path
-		actorPath := address.New("Test", "sys", "host", ports[0])
 
-		// create the actor ref
-		pid, err := newPID(ctx, actorPath, actor,
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger))
+		actorSystem, err := NewActorSystem("testSys",
+			WithRemoting(host, int32(ports[0])),
+			WithLogger(log.DiscardLogger))
+
+		require.NoError(t, err)
+		require.NotNil(t, actorSystem)
+
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
+
+		pid, err := actorSystem.Spawn(ctx, "test", newActor())
 
 		require.NoError(t, err)
 		assert.NotNil(t, pid)
@@ -320,23 +352,30 @@ func TestRestart(t *testing.T) {
 		// stop the actor
 		err = pid.Shutdown(ctx)
 		assert.NoError(t, err)
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 	t.Run("With restart an actor with PreStart failure", func(t *testing.T) {
 		ctx := context.TODO()
+		host := "127.0.0.1"
+		ports := dynaport.Get(1)
+
+		actorSystem, err := NewActorSystem("testSys",
+			WithRemoting(host, int32(ports[0])),
+			WithExpireActorAfter(time.Minute),
+			WithLogger(log.DiscardLogger))
+
+		require.NoError(t, err)
+		require.NotNil(t, actorSystem)
+
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
 
 		// create a Ping actor
 		actor := newRestart()
 		assert.NotNil(t, actor)
-		// create the actor path
-		ports := dynaport.Get(1)
-		// create the actor path
-		actorPath := address.New("Test", "sys", "host", ports[0])
 
-		// create the actor ref
-		pid, err := newPID(ctx, actorPath, actor,
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger),
-			withPassivationAfter(time.Minute))
+		pid, err := actorSystem.Spawn(ctx, "test", actor)
 
 		require.NoError(t, err)
 		assert.NotNil(t, pid)
@@ -352,6 +391,7 @@ func TestRestart(t *testing.T) {
 		// stop the actor
 		err = pid.Shutdown(ctx)
 		assert.NoError(t, err)
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 	t.Run("noSender cannot be restarted", func(t *testing.T) {
 		pid := &PID{
@@ -363,20 +403,28 @@ func TestRestart(t *testing.T) {
 	})
 	t.Run("With restart failed due to PostStop failure", func(t *testing.T) {
 		ctx := context.TODO()
+		host := "127.0.0.1"
+		ports := dynaport.Get(1)
+
+		actorSystem, err := NewActorSystem("testSys",
+			WithRemoting(host, int32(ports[0])),
+			WithExpireActorAfter(passivateAfter),
+			WithLogger(log.DiscardLogger))
+
+		require.NoError(t, err)
+		require.NotNil(t, actorSystem)
+
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
 
 		// create a Ping actor
 		actor := &postStopQA{}
 		assert.NotNil(t, actor)
-		// create the actor path
-		ports := dynaport.Get(1)
-		// create the actor path
-		actorPath := address.New("Test", "sys", "host", ports[0])
 
-		// create the actor ref
-		pid, err := newPID(ctx, actorPath, actor,
-			withInitMaxRetries(1),
-			withPassivationAfter(passivateAfter),
-			withCustomLogger(log.DiscardLogger))
+		pid, err := actorSystem.Spawn(ctx, "test", actor)
+		require.NoError(t, err)
+		assert.NotNil(t, pid)
 
 		require.NoError(t, err)
 		assert.NotNil(t, pid)
@@ -391,24 +439,28 @@ func TestRestart(t *testing.T) {
 		err = pid.Restart(ctx)
 		assert.Error(t, err)
 		assert.False(t, pid.IsRunning())
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 }
 func TestSupervisorStrategy(t *testing.T) {
 	t.Run("With stop as supervisor directive", func(t *testing.T) {
-		// create a test context
 		ctx := context.TODO()
-		// create the actor path
+		host := "127.0.0.1"
 		ports := dynaport.Get(1)
-		// create the actor path
-		actorPath := address.New("Test", "sys", "host", ports[0])
 
-		// create the parent actor
-		parent, err := newPID(ctx, actorPath,
-			newTestSupervisor(),
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger),
-			withSupervisorDirective(NewStopDirective()))
+		actorSystem, err := NewActorSystem("testSys",
+			WithRemoting(host, int32(ports[0])),
+			WithExpireActorAfter(passivateAfter),
+			WithLogger(log.DiscardLogger))
+
+		require.NoError(t, err)
+		require.NotNil(t, actorSystem)
 
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
+
+		parent, err := actorSystem.Spawn(ctx, "test", newTestSupervisor())
 		require.NoError(t, err)
 		assert.NotNil(t, parent)
 
@@ -429,23 +481,26 @@ func TestSupervisorStrategy(t *testing.T) {
 		//stop the actor
 		err = parent.Shutdown(ctx)
 		assert.NoError(t, err)
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 	t.Run("With the default supervisor directive", func(t *testing.T) {
-		// create a test context
 		ctx := context.TODO()
-		// create the actor path
+		host := "127.0.0.1"
 		ports := dynaport.Get(1)
-		// create the actor path
-		actorPath := address.New("Test", "sys", "host", ports[0])
 
-		// create the parent actor
-		parent, err := newPID(ctx,
-			actorPath,
-			newTestSupervisor(),
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger),
-			withPassivationDisabled())
+		actorSystem, err := NewActorSystem("testSys",
+			WithRemoting(host, int32(ports[0])),
+			WithPassivationDisabled(),
+			WithLogger(log.DiscardLogger))
 
+		require.NoError(t, err)
+		require.NotNil(t, actorSystem)
+
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
+
+		parent, err := actorSystem.Spawn(ctx, "test", newTestSupervisor())
 		require.NoError(t, err)
 		assert.NotNil(t, parent)
 
@@ -470,25 +525,26 @@ func TestSupervisorStrategy(t *testing.T) {
 		//stop the actor
 		err = parent.Shutdown(ctx)
 		assert.NoError(t, err)
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 	t.Run("With default strategy with child actor shutdown failure", func(t *testing.T) {
-		// create a test context
 		ctx := context.TODO()
-		// create the actor path
+		host := "127.0.0.1"
 		ports := dynaport.Get(1)
-		// create the actor path
-		actorPath := address.New("Test", "sys", "host", ports[0])
 
-		// create the parent actor
-		parent, err := newPID(ctx,
-			actorPath,
-			newTestSupervisor(),
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger),
-			withPassivationDisabled(),
-			withSupervisorDirective(new(unhandledSupervisorDirective)), // only for test to handle default case
-		)
+		actorSystem, err := NewActorSystem("testSys",
+			WithRemoting(host, int32(ports[0])),
+			WithPassivationDisabled(),
+			WithLogger(log.DiscardLogger))
+
+		require.NoError(t, err)
+		require.NotNil(t, actorSystem)
+
+		require.NoError(t, actorSystem.Start(ctx))
 
+		lib.Pause(time.Second)
+
+		parent, err := actorSystem.Spawn(ctx, "test", newTestSupervisor(), WithSupervisor(new(unhandledSupervisorDirective)))
 		require.NoError(t, err)
 		assert.NotNil(t, parent)
 
@@ -513,24 +569,26 @@ func TestSupervisorStrategy(t *testing.T) {
 		//stop the actor
 		err = parent.Shutdown(ctx)
 		assert.NoError(t, err)
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 	t.Run("With stop as supervisor directive with child actor shutdown failure", func(t *testing.T) {
-		// create a test context
 		ctx := context.TODO()
-		// create the actor path
+		host := "127.0.0.1"
 		ports := dynaport.Get(1)
-		// create the actor path
-		actorPath := address.New("Test", "sys", "host", ports[0])
 
-		// create the parent actor
-		parent, err := newPID(ctx,
-			actorPath,
-			newTestSupervisor(),
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger),
-			withSupervisorDirective(DefaultSupervisoryStrategy),
-			withPassivationDisabled(),
-		)
+		actorSystem, err := NewActorSystem("testSys",
+			WithRemoting(host, int32(ports[0])),
+			WithPassivationDisabled(),
+			WithLogger(log.DiscardLogger))
+
+		require.NoError(t, err)
+		require.NotNil(t, actorSystem)
+
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
+
+		parent, err := actorSystem.Spawn(ctx, "test", newTestSupervisor(), WithSupervisor(DefaultSupervisoryStrategy))
 
 		require.NoError(t, err)
 		assert.NotNil(t, parent)
@@ -556,26 +614,26 @@ func TestSupervisorStrategy(t *testing.T) {
 		//stop the actor
 		err = parent.Shutdown(ctx)
 		assert.NoError(t, err)
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 	t.Run("With restart as supervisor strategy", func(t *testing.T) {
-		// create a test context
 		ctx := context.TODO()
-
-		logger := log.DiscardLogger
-		// create the actor path
+		host := "127.0.0.1"
 		ports := dynaport.Get(1)
-		// create the actor path
-		actorPath := address.New("Test", "sys", "host", ports[0])
-		// create the parent actor
-		parent, err := newPID(ctx,
-			actorPath,
-			newTestSupervisor(),
-			withInitMaxRetries(1),
-			withCustomLogger(logger),
-			withPassivationDisabled(),
-			withSupervisorDirective(NewRestartDirective()),
-		)
 
+		actorSystem, err := NewActorSystem("testSys",
+			WithRemoting(host, int32(ports[0])),
+			WithPassivationDisabled(),
+			WithLogger(log.DiscardLogger))
+
+		require.NoError(t, err)
+		require.NotNil(t, actorSystem)
+
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
+
+		parent, err := actorSystem.Spawn(ctx, "test", newTestSupervisor(), WithSupervisor(NewRestartDirective()))
 		require.NoError(t, err)
 		require.NotNil(t, parent)
 
@@ -602,23 +660,26 @@ func TestSupervisorStrategy(t *testing.T) {
 		//stop the actor
 		err = parent.Shutdown(ctx)
 		assert.NoError(t, err)
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 	t.Run("With no strategy set will default to a Shutdown", func(t *testing.T) {
-		// create a test context
 		ctx := context.TODO()
-		// create the actor path
+		host := "127.0.0.1"
 		ports := dynaport.Get(1)
-		// create the actor path
-		actorPath := address.New("Test", "sys", "host", ports[0])
 
-		// create the parent actor
-		parent, err := newPID(ctx,
-			actorPath,
-			newTestSupervisor(),
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger),
-			withPassivationDisabled(),
-		)
+		actorSystem, err := NewActorSystem("testSys",
+			WithRemoting(host, int32(ports[0])),
+			WithPassivationDisabled(),
+			WithLogger(log.DiscardLogger))
+
+		require.NoError(t, err)
+		require.NotNil(t, actorSystem)
+
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
+
+		parent, err := actorSystem.Spawn(ctx, "test", newTestSupervisor())
 
 		require.NoError(t, err)
 		assert.NotNil(t, parent)
@@ -642,25 +703,26 @@ func TestSupervisorStrategy(t *testing.T) {
 		//stop the actor
 		err = parent.Shutdown(ctx)
 		assert.NoError(t, err)
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 	t.Run("With resume as supervisor strategy", func(t *testing.T) {
-		// create a test context
 		ctx := context.TODO()
-
-		logger := log.DiscardLogger
-		// create the actor path
+		host := "127.0.0.1"
 		ports := dynaport.Get(1)
-		actorPath := address.New("Test", "sys", "host", ports[0])
-		// create the parent actor
-		parent, err := newPID(ctx,
-			actorPath,
-			newTestSupervisor(),
-			withInitMaxRetries(1),
-			withCustomLogger(logger),
-			withPassivationDisabled(),
-			withSupervisorDirective(NewResumeDirective()),
-		)
 
+		actorSystem, err := NewActorSystem("testSys",
+			WithRemoting(host, int32(ports[0])),
+			WithPassivationDisabled(),
+			WithLogger(log.DiscardLogger))
+
+		require.NoError(t, err)
+		require.NotNil(t, actorSystem)
+
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
+
+		parent, err := actorSystem.Spawn(ctx, "test", newTestSupervisor(), WithSupervisor(NewResumeDirective()))
 		require.NoError(t, err)
 		assert.NotNil(t, parent)
 
@@ -689,30 +751,30 @@ func TestSupervisorStrategy(t *testing.T) {
 		//stop the actor
 		err = parent.Shutdown(ctx)
 		assert.NoError(t, err)
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 	t.Run("With restart with limit as supervisor strategy", func(t *testing.T) {
-		// create a test context
 		ctx := context.TODO()
-
-		logger := log.DiscardLogger
-		// create the actor path
+		host := "127.0.0.1"
 		ports := dynaport.Get(1)
-		actorPath := address.New("Test", "sys", "host", ports[0])
+
+		actorSystem, err := NewActorSystem("testSys",
+			WithRemoting(host, int32(ports[0])),
+			WithPassivationDisabled(),
+			WithLogger(log.DiscardLogger))
+
+		require.NoError(t, err)
+		require.NotNil(t, actorSystem)
+
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
 
 		// create the directive
 		restart := NewRestartDirective()
 		restart.WithLimit(2, time.Minute)
 
-		// create the parent actor
-		parent, err := newPID(ctx,
-			actorPath,
-			newTestSupervisor(),
-			withInitMaxRetries(1),
-			withCustomLogger(logger),
-			withPassivationDisabled(),
-			withSupervisorDirective(restart),
-		)
-
+		parent, err := actorSystem.Spawn(ctx, "test", newTestSupervisor(), WithSupervisor(restart))
 		require.NoError(t, err)
 		require.NotNil(t, parent)
 
@@ -737,36 +799,43 @@ func TestSupervisorStrategy(t *testing.T) {
 		//stop the actor
 		err = parent.Shutdown(ctx)
 		assert.NoError(t, err)
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 }
 func TestMessaging(t *testing.T) {
 	t.Run("With happy", func(t *testing.T) {
 		ctx := context.TODO()
-		// create a Ping actor
-		opts := []pidOption{
-			withInitMaxRetries(1),
-			withCustomLogger(log.DefaultLogger),
-		}
+		host := "127.0.0.1"
 		ports := dynaport.Get(1)
-		// create the actor path
-		actor1 := &exchanger{}
-		actorPath1 := address.New("Exchange1", "sys", "host", ports[0])
-		pid1, err := newPID(ctx, actorPath1, actor1, opts...)
+
+		actorSystem, err := NewActorSystem("testSys",
+			WithRemoting(host, int32(ports[0])),
+			WithPassivationDisabled(),
+			WithJanitorInterval(time.Minute),
+			WithLogger(log.DiscardLogger))
 
+		require.NoError(t, err)
+		require.NotNil(t, actorSystem)
+
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
+
+		pid1, err := actorSystem.Spawn(ctx, "Exchange1", &exchanger{})
 		require.NoError(t, err)
 		require.NotNil(t, pid1)
 
-		actor2 := &exchanger{}
-		actorPath2 := address.New("Exchange2", "sys", "host", ports[0])
-		pid2, err := newPID(ctx, actorPath2, actor2, opts...)
+		pid2, err := actorSystem.Spawn(ctx, "Exchange2", &exchanger{})
 		require.NoError(t, err)
 		require.NotNil(t, pid2)
 
+		lib.Pause(time.Second)
+
 		err = pid1.Tell(ctx, pid2, new(testpb.TestSend))
 		require.NoError(t, err)
 
 		// send an ask
-		reply, err := pid1.Ask(ctx, pid2, new(testpb.TestReply), 20*time.Second)
+		reply, err := pid1.Ask(ctx, pid2, new(testpb.TestReply), time.Second)
 		require.NoError(t, err)
 		require.NotNil(t, reply)
 		expected := new(testpb.Reply)
@@ -778,35 +847,43 @@ func TestMessaging(t *testing.T) {
 		err = Tell(ctx, pid1, new(testpb.TestBye))
 		require.NoError(t, err)
 
-		assert.Eventually(t, func() bool {
-			return pid1.IsRunning()
-		}, 2*time.Second, time.Second)
+		lib.Pause(time.Second)
 
+		assert.False(t, pid1.IsRunning())
 		assert.True(t, pid2.IsRunning())
 
 		err = Tell(ctx, pid2, new(testpb.TestBye))
+		assert.NoError(t, err)
 		lib.Pause(time.Second)
 		assert.False(t, pid2.IsRunning())
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 	t.Run("With Ask invalid timeout", func(t *testing.T) {
 		ctx := context.TODO()
-		// create a Ping actor
-		opts := []pidOption{
-			withInitMaxRetries(1),
-			withCustomLogger(log.DefaultLogger),
-		}
+		host := "127.0.0.1"
 		ports := dynaport.Get(1)
+
+		actorSystem, err := NewActorSystem("testSys",
+			WithRemoting(host, int32(ports[0])),
+			WithPassivationDisabled(),
+			WithLogger(log.DiscardLogger))
+
+		require.NoError(t, err)
+		require.NotNil(t, actorSystem)
+
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
+
 		// create the actor path
 		actor1 := &exchanger{}
-		actorPath1 := address.New("Exchange1", "sys", "host", ports[0])
-		pid1, err := newPID(ctx, actorPath1, actor1, opts...)
+		pid1, err := actorSystem.Spawn(ctx, "Exchange1", actor1)
 
 		require.NoError(t, err)
 		require.NotNil(t, pid1)
 
 		actor2 := &exchanger{}
-		actorPath2 := address.New("Exchange2", "sys", "host", ports[0])
-		pid2, err := newPID(ctx, actorPath2, actor2, opts...)
+		pid2, err := actorSystem.Spawn(ctx, "Exchange2", actor2)
 		require.NoError(t, err)
 		require.NotNil(t, pid2)
 
@@ -817,26 +894,34 @@ func TestMessaging(t *testing.T) {
 
 		require.NoError(t, pid1.Shutdown(ctx))
 		require.NoError(t, pid2.Shutdown(ctx))
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 	t.Run("With Ask when not ready", func(t *testing.T) {
 		ctx := context.TODO()
-		// create a Ping actor
-		opts := []pidOption{
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger),
-		}
+		host := "127.0.0.1"
 		ports := dynaport.Get(1)
+
+		actorSystem, err := NewActorSystem("testSys",
+			WithRemoting(host, int32(ports[0])),
+			WithPassivationDisabled(),
+			WithJanitorInterval(time.Minute),
+			WithLogger(log.DiscardLogger))
+
+		require.NoError(t, err)
+		require.NotNil(t, actorSystem)
+
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
+
 		// create the actor path
 		actor1 := &exchanger{}
-		actorPath1 := address.New("Exchange1", "sys", "host", ports[0])
-		pid1, err := newPID(ctx, actorPath1, actor1, opts...)
-
+		pid1, err := actorSystem.Spawn(ctx, "Exchange1", actor1)
 		require.NoError(t, err)
 		require.NotNil(t, pid1)
 
 		actor2 := &exchanger{}
-		actorPath2 := address.New("Exchange2", "sys", "host", ports[0])
-		pid2, err := newPID(ctx, actorPath2, actor2, opts...)
+		pid2, err := actorSystem.Spawn(ctx, "Exchange2", actor2)
 		require.NoError(t, err)
 		require.NotNil(t, pid2)
 
@@ -855,26 +940,34 @@ func TestMessaging(t *testing.T) {
 
 		err = Tell(ctx, pid1, new(testpb.TestBye))
 		require.NoError(t, err)
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 	t.Run("With Tell when not ready", func(t *testing.T) {
 		ctx := context.TODO()
-		// create a Ping actor
-		opts := []pidOption{
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger),
-		}
+		host := "127.0.0.1"
 		ports := dynaport.Get(1)
 
+		actorSystem, err := NewActorSystem("testSys",
+			WithRemoting(host, int32(ports[0])),
+			WithPassivationDisabled(),
+			WithJanitorInterval(time.Minute),
+			WithLogger(log.DiscardLogger))
+
+		require.NoError(t, err)
+		require.NotNil(t, actorSystem)
+
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
+
 		// create the actor path
 		actor1 := &exchanger{}
-		actorPath1 := address.New("Exchange1", "sys", "host", ports[0])
-		pid1, err := newPID(ctx, actorPath1, actor1, opts...)
+		pid1, err := actorSystem.Spawn(ctx, "Exchange1", actor1)
 		require.NoError(t, err)
 		require.NotNil(t, pid1)
 
 		actor2 := &exchanger{}
-		actorPath2 := address.New("Exchange2", "sys", "host", ports[0])
-		pid2, err := newPID(ctx, actorPath2, actor2, opts...)
+		pid2, err := actorSystem.Spawn(ctx, "Exchange2", actor2)
 		require.NoError(t, err)
 		require.NotNil(t, pid2)
 
@@ -892,27 +985,35 @@ func TestMessaging(t *testing.T) {
 
 		err = Tell(ctx, pid1, new(testpb.TestBye))
 		require.NoError(t, err)
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 	t.Run("With Ask timeout", func(t *testing.T) {
 		ctx := context.TODO()
-		// create a Ping actor
-		opts := []pidOption{
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger),
-		}
+		host := "127.0.0.1"
 		ports := dynaport.Get(1)
 
+		actorSystem, err := NewActorSystem("testSys",
+			WithRemoting(host, int32(ports[0])),
+			WithPassivationDisabled(),
+			WithJanitorInterval(time.Minute),
+			WithLogger(log.DiscardLogger))
+
+		require.NoError(t, err)
+		require.NotNil(t, actorSystem)
+
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
+
 		// create the actor path
 		actor1 := &exchanger{}
-		actorPath1 := address.New("Exchange1", "sys", "host", ports[0])
-		pid1, err := newPID(ctx, actorPath1, actor1, opts...)
+		pid1, err := actorSystem.Spawn(ctx, "Exchange1", actor1)
 
 		require.NoError(t, err)
 		require.NotNil(t, pid1)
 
 		actor2 := newActor()
-		actorPath2 := address.New("Exchange2", "sys", "host", ports[0])
-		pid2, err := newPID(ctx, actorPath2, actor2, opts...)
+		pid2, err := actorSystem.Spawn(ctx, "Exchange2", actor2)
 		require.NoError(t, err)
 		require.NotNil(t, pid2)
 
@@ -938,6 +1039,7 @@ func TestMessaging(t *testing.T) {
 		lib.Pause(time.Second)
 		assert.NoError(t, pid2.Shutdown(ctx))
 		assert.False(t, pid2.IsRunning())
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 }
 func TestRemoting(t *testing.T) {
@@ -1069,17 +1171,24 @@ func TestRemoting(t *testing.T) {
 }
 func TestActorHandle(t *testing.T) {
 	ctx := context.TODO()
-	// create the actor path
+	host := "127.0.0.1"
 	ports := dynaport.Get(1)
-	actorPath := address.New("Test", "sys", "host", ports[0])
+
+	actorSystem, err := NewActorSystem("testSys",
+		WithRemoting(host, int32(ports[0])),
+		WithPassivationDisabled(),
+		WithJanitorInterval(time.Minute),
+		WithLogger(log.DiscardLogger))
+
+	require.NoError(t, err)
+	require.NotNil(t, actorSystem)
+
+	require.NoError(t, actorSystem.Start(ctx))
+
+	lib.Pause(time.Second)
 
 	// create the actor ref
-	pid, err := newPID(
-		ctx,
-		actorPath,
-		&exchanger{},
-		withInitMaxRetries(1),
-		withCustomLogger(log.DiscardLogger))
+	pid, err := actorSystem.Spawn(ctx, "Exchanger", &exchanger{})
 
 	require.NoError(t, err)
 	assert.NotNil(t, pid)
@@ -1091,81 +1200,163 @@ func TestActorHandle(t *testing.T) {
 	// stop the actor
 	err = pid.Shutdown(ctx)
 	assert.NoError(t, err)
+	lib.Pause(time.Second)
+	assert.NoError(t, actorSystem.Stop(ctx))
 }
 func TestPIDActorSystem(t *testing.T) {
 	ctx := context.TODO()
-	// create the actor path
+	host := "127.0.0.1"
 	ports := dynaport.Get(1)
-	actorPath := address.New("Test", "sys", "host", ports[0])
+
+	actorSystem, err := NewActorSystem("testSys",
+		WithRemoting(host, int32(ports[0])),
+		WithPassivationDisabled(),
+		WithJanitorInterval(time.Minute),
+		WithLogger(log.DiscardLogger))
+
+	require.NoError(t, err)
+	require.NotNil(t, actorSystem)
+
+	require.NoError(t, actorSystem.Start(ctx))
+
+	lib.Pause(time.Second)
 
 	// create the actor ref
-	pid, err := newPID(
-		ctx,
-		actorPath,
-		&exchanger{},
-		withInitMaxRetries(1),
-		withCustomLogger(log.DiscardLogger))
+	pid, err := actorSystem.Spawn(ctx, "Exchanger", &exchanger{})
 
 	require.NoError(t, err)
 	assert.NotNil(t, pid)
 	sys := pid.ActorSystem()
-	assert.Nil(t, sys)
+	require.NotNil(t, sys)
 	// stop the actor
 	err = pid.Shutdown(ctx)
-	assert.NoError(t, err)
+	require.NoError(t, err)
+	lib.Pause(time.Second)
+	assert.NoError(t, actorSystem.Stop(ctx))
 }
 func TestSpawnChild(t *testing.T) {
 	t.Run("With restarting child actor", func(t *testing.T) {
-		// create a test context
 		ctx := context.TODO()
-		// create the actor path
+		host := "127.0.0.1"
 		ports := dynaport.Get(1)
-		actorPath := address.New("Test", "sys", "host", ports[0])
 
-		// create the parent actor
-		parent, err := newPID(ctx, actorPath,
-			newTestSupervisor(),
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger))
+		actorSystem, err := NewActorSystem("testSys",
+			WithRemoting(host, int32(ports[0])),
+			WithPassivationDisabled(),
+			WithLogger(log.DefaultLogger))
+
+		require.NoError(t, err)
+		require.NotNil(t, actorSystem)
+
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
 
+		// create the parent actor
+		parent, err := actorSystem.Spawn(ctx, "Parent", newTestSupervisor())
 		require.NoError(t, err)
 		assert.NotNil(t, parent)
 
+		lib.Pause(time.Second)
+
 		// create the child actor
 		child, err := parent.SpawnChild(ctx, "SpawnChild", newTestSupervised())
 		assert.NoError(t, err)
 		assert.NotNil(t, child)
 
-		assert.Len(t, parent.Children(), 1)
+		lib.Pause(time.Second)
+
+		require.Len(t, parent.Children(), 1)
 
 		// stop the child actor
-		assert.NoError(t, child.Shutdown(ctx))
+		require.NoError(t, child.Shutdown(ctx))
+
+		lib.Pause(time.Second)
+		require.False(t, child.IsRunning())
+		require.Empty(t, parent.Children())
 
-		lib.Pause(100 * time.Millisecond)
 		// create the child actor
 		child, err = parent.SpawnChild(ctx, "SpawnChild", newTestSupervised())
 		assert.NoError(t, err)
 		assert.NotNil(t, child)
 
-		lib.Pause(100 * time.Millisecond)
+		lib.Pause(time.Second)
 
 		assert.Len(t, parent.Children(), 1)
 		//stop the actor
 		err = parent.Shutdown(ctx)
 		assert.NoError(t, err)
+		lib.Pause(time.Second)
+		assert.NoError(t, actorSystem.Stop(ctx))
+	})
+	t.Run("With empty children when actor is not running or does not exist", func(t *testing.T) {
+		ctx := context.TODO()
+		host := "127.0.0.1"
+		ports := dynaport.Get(1)
+
+		actorSystem, err := NewActorSystem("testSys",
+			WithRemoting(host, int32(ports[0])),
+			WithPassivationDisabled(),
+			WithJanitorInterval(100*time.Millisecond),
+			WithLogger(log.DefaultLogger))
+
+		require.NoError(t, err)
+		require.NotNil(t, actorSystem)
+
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
+
+		// create the parent actor
+		parent, err := actorSystem.Spawn(ctx, "Parent", newTestSupervisor())
+		require.NoError(t, err)
+		assert.NotNil(t, parent)
+
+		lib.Pause(time.Second)
+
+		// create the child actor
+		child, err := parent.SpawnChild(ctx, "SpawnChild", newTestSupervised())
+		assert.NoError(t, err)
+		assert.NotNil(t, child)
+
+		lib.Pause(time.Second)
+
+		require.Len(t, parent.Children(), 1)
+
+		// stop the child actor
+		require.NoError(t, child.Shutdown(ctx))
+
+		lib.Pause(time.Second)
+		require.False(t, child.IsRunning())
+		require.Empty(t, parent.Children())
+
+		// stop the parent actor
+		require.NoError(t, parent.Shutdown(ctx))
+		lib.Pause(time.Second)
+
+		require.Empty(t, parent.Children())
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 	t.Run("With starting child actor with a different mailbox", func(t *testing.T) {
-		// create a test context
 		ctx := context.TODO()
-		// create the actor path
+		host := "127.0.0.1"
 		ports := dynaport.Get(1)
-		actorPath := address.New("Test", "sys", "host", ports[0])
+
+		actorSystem, err := NewActorSystem("testSys",
+			WithRemoting(host, int32(ports[0])),
+			WithPassivationDisabled(),
+			WithJanitorInterval(time.Minute),
+			WithLogger(log.DiscardLogger))
+
+		require.NoError(t, err)
+		require.NotNil(t, actorSystem)
+
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
 
 		// create the parent actor
-		parent, err := newPID(ctx, actorPath,
-			newTestSupervisor(),
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger))
+		parent, err := actorSystem.Spawn(ctx, "Parent", newTestSupervisor())
 
 		require.NoError(t, err)
 		assert.NotNil(t, parent)
@@ -1182,19 +1373,29 @@ func TestSpawnChild(t *testing.T) {
 		//stop the actor
 		err = parent.Shutdown(ctx)
 		assert.NoError(t, err)
+		lib.Pause(time.Second)
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 	t.Run("With restarting child actor when not shutdown", func(t *testing.T) {
-		// create a test context
 		ctx := context.TODO()
-		// create the actor path
+		host := "127.0.0.1"
 		ports := dynaport.Get(1)
-		actorPath := address.New("Test", "sys", "host", ports[0])
+
+		actorSystem, err := NewActorSystem("testSys",
+			WithRemoting(host, int32(ports[0])),
+			WithPassivationDisabled(),
+			WithJanitorInterval(time.Minute),
+			WithLogger(log.DiscardLogger))
+
+		require.NoError(t, err)
+		require.NotNil(t, actorSystem)
+
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
 
 		// create the parent actor
-		parent, err := newPID(ctx, actorPath,
-			newTestSupervisor(),
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger))
+		parent, err := actorSystem.Spawn(ctx, "Parent", newTestSupervisor())
 
 		require.NoError(t, err)
 		assert.NotNil(t, parent)
@@ -1218,20 +1419,29 @@ func TestSpawnChild(t *testing.T) {
 		//stop the actor
 		err = parent.Shutdown(ctx)
 		assert.NoError(t, err)
+		lib.Pause(time.Second)
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 	t.Run("With parent not ready", func(t *testing.T) {
-		// create a test context
 		ctx := context.TODO()
-		// create the actor path
+		host := "127.0.0.1"
 		ports := dynaport.Get(1)
-		actorPath := address.New("Test", "sys", "host", ports[0])
 
-		// create the parent actor
-		parent, err := newPID(ctx, actorPath,
-			newTestSupervisor(),
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger))
+		actorSystem, err := NewActorSystem("testSys",
+			WithRemoting(host, int32(ports[0])),
+			WithPassivationDisabled(),
+			WithJanitorInterval(time.Minute),
+			WithLogger(log.DiscardLogger))
+
+		require.NoError(t, err)
+		require.NotNil(t, actorSystem)
+
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
 
+		// create the parent actor
+		parent, err := actorSystem.Spawn(ctx, "Parent", newTestSupervisor())
 		require.NoError(t, err)
 		assert.NotNil(t, parent)
 
@@ -1245,19 +1455,28 @@ func TestSpawnChild(t *testing.T) {
 		assert.Error(t, err)
 		assert.EqualError(t, err, ErrDead.Error())
 		assert.Nil(t, child)
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 	t.Run("With failed init", func(t *testing.T) {
-		// create a test context
 		ctx := context.TODO()
-		// create the actor path
+		host := "127.0.0.1"
 		ports := dynaport.Get(1)
-		actorPath := address.New("Test", "sys", "host", ports[0])
+
+		actorSystem, err := NewActorSystem("testSys",
+			WithRemoting(host, int32(ports[0])),
+			WithPassivationDisabled(),
+			WithJanitorInterval(time.Minute),
+			WithLogger(log.DiscardLogger))
+
+		require.NoError(t, err)
+		require.NotNil(t, actorSystem)
+
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
 
 		// create the parent actor
-		parent, err := newPID(ctx, actorPath,
-			newTestSupervisor(),
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger))
+		parent, err := actorSystem.Spawn(ctx, "Parent", newTestSupervisor())
 
 		require.NoError(t, err)
 		assert.NotNil(t, parent)
@@ -1271,26 +1490,33 @@ func TestSpawnChild(t *testing.T) {
 		//stop the actor
 		err = parent.Shutdown(ctx)
 		assert.NoError(t, err)
+		lib.Pause(time.Second)
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 	t.Run("With child created event published", func(t *testing.T) {
-		// create a test context
 		ctx := context.TODO()
-		// create the actor path
+		host := "127.0.0.1"
 		ports := dynaport.Get(1)
-		actorPath := address.New("Test", "sys", "host", ports[0])
 
-		eventsStream := eventstream.New()
+		actorSystem, err := NewActorSystem("testSys",
+			WithRemoting(host, int32(ports[0])),
+			WithPassivationDisabled(),
+			WithJanitorInterval(time.Minute),
+			WithLogger(log.DiscardLogger))
+
+		require.NoError(t, err)
+		require.NotNil(t, actorSystem)
+
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
 
 		// add a subscriber
-		subsriber := eventsStream.AddSubscriber()
-		eventsStream.Subscribe(subsriber, eventsTopic)
+		subsriber, err := actorSystem.Subscribe()
+		require.NoError(t, err)
 
 		// create the parent actor
-		parent, err := newPID(ctx, actorPath,
-			newTestSupervisor(),
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger),
-			withEventsStream(eventsStream))
+		parent, err := actorSystem.Spawn(ctx, "Parent", newTestSupervisor())
 
 		require.NoError(t, err)
 		assert.NotNil(t, parent)
@@ -1323,22 +1549,30 @@ func TestSpawnChild(t *testing.T) {
 		//stop the actor
 		err = parent.Shutdown(ctx)
 		assert.NoError(t, err)
+		lib.Pause(time.Second)
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 }
 func TestPoisonPill(t *testing.T) {
 	ctx := context.TODO()
-
-	// create the actor path
+	host := "127.0.0.1"
 	ports := dynaport.Get(1)
-	actorPath := address.New("Test", "sys", "host", ports[0])
+
+	actorSystem, err := NewActorSystem("testSys",
+		WithRemoting(host, int32(ports[0])),
+		WithPassivationDisabled(),
+		WithJanitorInterval(time.Minute),
+		WithLogger(log.DiscardLogger))
+
+	require.NoError(t, err)
+	require.NotNil(t, actorSystem)
+
+	require.NoError(t, actorSystem.Start(ctx))
+
+	lib.Pause(time.Second)
 
 	// create the actor ref
-	pid, err := newPID(
-		ctx,
-		actorPath,
-		newActor(),
-		withInitMaxRetries(1),
-		withCustomLogger(log.DiscardLogger))
+	pid, err := actorSystem.Spawn(ctx, "PoisonPill", newActor())
 
 	require.NoError(t, err)
 	assert.NotNil(t, pid)
@@ -1351,6 +1585,8 @@ func TestPoisonPill(t *testing.T) {
 	// wait for the graceful shutdown
 	lib.Pause(time.Second)
 	assert.False(t, pid.IsRunning())
+	lib.Pause(time.Second)
+	assert.NoError(t, actorSystem.Stop(ctx))
 }
 func TestRemoteLookup(t *testing.T) {
 	t.Run("With actor address not found", func(t *testing.T) {
@@ -1506,38 +1742,51 @@ func TestFailedPreStart(t *testing.T) {
 }
 func TestFailedPostStop(t *testing.T) {
 	ctx := context.TODO()
-
-	// create the actor path
+	host := "127.0.0.1"
 	ports := dynaport.Get(1)
-	actorPath := address.New("Test", "sys", "host", ports[0])
 
-	// create the actor ref
-	pid, err := newPID(
-		ctx,
-		actorPath,
-		&postStopQA{},
-		withInitMaxRetries(1),
-		withCustomLogger(log.DiscardLogger))
+	actorSystem, err := NewActorSystem("testSys",
+		WithRemoting(host, int32(ports[0])),
+		WithPassivationDisabled(),
+		WithJanitorInterval(time.Minute),
+		WithLogger(log.DiscardLogger))
+
+	require.NoError(t, err)
+	require.NotNil(t, actorSystem)
+
+	require.NoError(t, actorSystem.Start(ctx))
+
+	lib.Pause(time.Second)
+	pid, err := actorSystem.Spawn(ctx, "PostStop", &postStopQA{})
 
 	require.NoError(t, err)
 	assert.NotNil(t, pid)
 
 	assert.Error(t, pid.Shutdown(ctx))
+	lib.Pause(time.Second)
+	assert.NoError(t, actorSystem.Stop(ctx))
 }
 func TestShutdown(t *testing.T) {
 	t.Run("With Shutdown panic to child stop failure", func(t *testing.T) {
 		// create a test context
 		ctx := context.TODO()
-		// create the actor path
+		host := "127.0.0.1"
 		ports := dynaport.Get(1)
-		actorPath := address.New("Test", "sys", "host", ports[0])
 
-		// create the parent actor
-		parent, err := newPID(ctx, actorPath,
-			newTestSupervisor(),
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger))
+		actorSystem, err := NewActorSystem("testSys",
+			WithRemoting(host, int32(ports[0])),
+			WithPassivationDisabled(),
+			WithJanitorInterval(time.Minute),
+			WithLogger(log.DiscardLogger))
+
+		require.NoError(t, err)
+		require.NotNil(t, actorSystem)
+
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
 
+		parent, err := actorSystem.Spawn(ctx, "test", newTestSupervisor())
 		require.NoError(t, err)
 		assert.NotNil(t, parent)
 
@@ -1550,22 +1799,32 @@ func TestShutdown(t *testing.T) {
 
 		//stop the
 		assert.Error(t, parent.Shutdown(ctx))
+		lib.Pause(2 * time.Second)
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 }
 func TestBatchTell(t *testing.T) {
 	t.Run("With happy path", func(t *testing.T) {
 		ctx := context.TODO()
-		// create a Ping actor
-		opts := []pidOption{
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger),
-		}
+		host := "127.0.0.1"
+		ports := dynaport.Get(1)
+
+		actorSystem, err := NewActorSystem("testSys",
+			WithRemoting(host, int32(ports[0])),
+			WithPassivationDisabled(),
+			WithJanitorInterval(time.Minute),
+			WithLogger(log.DiscardLogger))
+
+		require.NoError(t, err)
+		require.NotNil(t, actorSystem)
+
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
 
 		// create the actor path
 		actor := newActor()
-		ports := dynaport.Get(1)
-		actorPath := address.New("Test", "sys", "host", ports[0])
-		pid, err := newPID(ctx, actorPath, actor, opts...)
+		pid, err := actorSystem.Spawn(ctx, "test", actor)
 		require.NoError(t, err)
 		require.NotNil(t, pid)
 
@@ -1578,20 +1837,30 @@ func TestBatchTell(t *testing.T) {
 		// wait a while because exchange is ongoing
 		lib.Pause(time.Second)
 		assert.NoError(t, pid.Shutdown(ctx))
+		lib.Pause(time.Second)
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 	t.Run("With a Tell behavior", func(t *testing.T) {
 		ctx := context.TODO()
-		// create a Ping actor
-		opts := []pidOption{
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger),
-		}
+		host := "127.0.0.1"
+		ports := dynaport.Get(1)
+
+		actorSystem, err := NewActorSystem("testSys",
+			WithRemoting(host, int32(ports[0])),
+			WithPassivationDisabled(),
+			WithJanitorInterval(time.Minute),
+			WithLogger(log.DiscardLogger))
+
+		require.NoError(t, err)
+		require.NotNil(t, actorSystem)
+
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
 
 		// create the actor path
 		actor := newActor()
-		ports := dynaport.Get(1)
-		actorPath := address.New("Test", "sys", "host", ports[0])
-		pid, err := newPID(ctx, actorPath, actor, opts...)
+		pid, err := actorSystem.Spawn(ctx, "test", actor)
 		require.NoError(t, err)
 		require.NotNil(t, pid)
 
@@ -1604,44 +1873,63 @@ func TestBatchTell(t *testing.T) {
 		// wait a while because exchange is ongoing
 		lib.Pause(time.Second)
 		assert.NoError(t, pid.Shutdown(ctx))
+		lib.Pause(time.Second)
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 	t.Run("With a dead actor", func(t *testing.T) {
 		ctx := context.TODO()
-		// create a Ping actor
-		opts := []pidOption{
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger),
-		}
+		host := "127.0.0.1"
+		ports := dynaport.Get(1)
+
+		actorSystem, err := NewActorSystem("testSys",
+			WithRemoting(host, int32(ports[0])),
+			WithPassivationDisabled(),
+			WithJanitorInterval(time.Minute),
+			WithLogger(log.DiscardLogger))
+
+		require.NoError(t, err)
+		require.NotNil(t, actorSystem)
+
+		require.NoError(t, actorSystem.Start(ctx))
 
+		lib.Pause(time.Second)
 		// create the actor path
 		actor := newActor()
-		ports := dynaport.Get(1)
-		actorPath := address.New("Test", "sys", "host", ports[0])
-		pid, err := newPID(ctx, actorPath, actor, opts...)
+		pid, err := actorSystem.Spawn(ctx, "test", actor)
 		require.NoError(t, err)
 		require.NotNil(t, pid)
 
 		lib.Pause(time.Second)
 		assert.NoError(t, pid.Shutdown(ctx))
 
+		lib.Pause(time.Second)
 		// batch tell
 		require.Error(t, pid.BatchTell(ctx, pid, new(testpb.TestSend)))
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 }
 func TestBatchAsk(t *testing.T) {
 	t.Run("With happy path", func(t *testing.T) {
 		ctx := context.TODO()
-		// create a Ping actor
-		opts := []pidOption{
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger),
-		}
+		host := "127.0.0.1"
+		ports := dynaport.Get(1)
+
+		actorSystem, err := NewActorSystem("testSys",
+			WithRemoting(host, int32(ports[0])),
+			WithPassivationDisabled(),
+			WithJanitorInterval(time.Minute),
+			WithLogger(log.DiscardLogger))
+
+		require.NoError(t, err)
+		require.NotNil(t, actorSystem)
+
+		require.NoError(t, actorSystem.Start(ctx))
 
+		lib.Pause(time.Second)
 		// create the actor path
 		actor := &exchanger{}
-		ports := dynaport.Get(1)
-		actorPath := address.New("Test", "sys", "host", ports[0])
-		pid, err := newPID(ctx, actorPath, actor, opts...)
+
+		pid, err := actorSystem.Spawn(ctx, "test", actor)
 		require.NoError(t, err)
 		require.NotNil(t, pid)
 
@@ -1658,44 +1946,66 @@ func TestBatchAsk(t *testing.T) {
 		// wait a while because exchange is ongoing
 		lib.Pause(time.Second)
 		assert.NoError(t, pid.Shutdown(ctx))
+		lib.Pause(time.Second)
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 	t.Run("With a dead actor", func(t *testing.T) {
 		ctx := context.TODO()
-		// create a Ping actor
-		opts := []pidOption{
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger),
-		}
+		host := "127.0.0.1"
+		ports := dynaport.Get(1)
+
+		actorSystem, err := NewActorSystem("testSys",
+			WithRemoting(host, int32(ports[0])),
+			WithPassivationDisabled(),
+			WithJanitorInterval(time.Minute),
+			WithLogger(log.DiscardLogger))
+
+		require.NoError(t, err)
+		require.NotNil(t, actorSystem)
+
+		require.NoError(t, actorSystem.Start(ctx))
 
+		lib.Pause(time.Second)
 		// create the actor path
 		actor := &exchanger{}
-		ports := dynaport.Get(1)
-		actorPath := address.New("Test", "sys", "host", ports[0])
-		pid, err := newPID(ctx, actorPath, actor, opts...)
+
+		pid, err := actorSystem.Spawn(ctx, "test", actor)
 		require.NoError(t, err)
 		require.NotNil(t, pid)
 
 		lib.Pause(time.Second)
 		assert.NoError(t, pid.Shutdown(ctx))
 
+		lib.Pause(time.Second)
+
 		// batch ask
 		responses, err := pid.BatchAsk(ctx, pid, []proto.Message{new(testpb.TestReply), new(testpb.TestReply)}, replyTimeout)
 		require.Error(t, err)
 		require.Nil(t, responses)
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 	t.Run("With a timeout", func(t *testing.T) {
 		ctx := context.TODO()
-		// create a Ping actor
-		opts := []pidOption{
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger),
-		}
+		host := "127.0.0.1"
+		ports := dynaport.Get(1)
+
+		actorSystem, err := NewActorSystem("testSys",
+			WithRemoting(host, int32(ports[0])),
+			WithPassivationDisabled(),
+			WithJanitorInterval(time.Minute),
+			WithLogger(log.DiscardLogger))
+
+		require.NoError(t, err)
+		require.NotNil(t, actorSystem)
+
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
 
 		// create the actor path
 		actor := newActor()
-		ports := dynaport.Get(1)
-		actorPath := address.New("Test", "sys", "host", ports[0])
-		pid, err := newPID(ctx, actorPath, actor, opts...)
+
+		pid, err := actorSystem.Spawn(ctx, "test", actor)
 		require.NoError(t, err)
 		require.NotNil(t, pid)
 
@@ -1707,6 +2017,8 @@ func TestBatchAsk(t *testing.T) {
 		// wait a while because exchange is ongoing
 		lib.Pause(time.Second)
 		assert.NoError(t, pid.Shutdown(ctx))
+		lib.Pause(time.Second)
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 }
 func TestRemoteReSpawn(t *testing.T) {
@@ -1841,6 +2153,7 @@ func TestRemoteStop(t *testing.T) {
 		sys, err := NewActorSystem("test",
 			WithLogger(logger),
 			WithPassivationDisabled(),
+			WithJanitorInterval(time.Minute),
 			WithRemoting(host, int32(remotingPort)),
 		)
 		// assert there are no error
@@ -1880,6 +2193,7 @@ func TestRemoteStop(t *testing.T) {
 		sys, err := NewActorSystem("test",
 			WithLogger(logger),
 			WithPassivationDisabled(),
+			WithJanitorInterval(time.Minute),
 			WithRemoting(host, int32(remotingPort)),
 		)
 		// assert there are no error
@@ -1986,34 +2300,7 @@ func TestRemoteStop(t *testing.T) {
 		})
 	})
 }
-func TestID(t *testing.T) {
-	ctx := context.TODO()
-	// create the actor path
-	ports := dynaport.Get(1)
-	actorPath := address.New("Test", "sys", "host", ports[0])
 
-	// create the actor ref
-	pid, err := newPID(
-		ctx,
-		actorPath,
-		&exchanger{},
-		withInitMaxRetries(1),
-		withCustomLogger(log.DiscardLogger))
-
-	require.NoError(t, err)
-	assert.NotNil(t, pid)
-	sys := pid.ActorSystem()
-	assert.Nil(t, sys)
-
-	expected := actorPath.String()
-	actual := pid.ID()
-
-	require.Equal(t, expected, actual)
-
-	// stop the actor
-	err = pid.Shutdown(ctx)
-	assert.NoError(t, err)
-}
 func TestEquals(t *testing.T) {
 	t.Run("case 1", func(t *testing.T) {
 		ctx := context.TODO()
@@ -2060,6 +2347,7 @@ func TestRemoteSpawn(t *testing.T) {
 		sys, err := NewActorSystem("test",
 			WithLogger(logger),
 			WithPassivationDisabled(),
+			WithJanitorInterval(time.Minute),
 			WithRemoting(host, int32(remotingPort)),
 		)
 		// assert there are no error
@@ -2258,54 +2546,64 @@ func TestRemoteSpawn(t *testing.T) {
 }
 func TestName(t *testing.T) {
 	ctx := context.TODO()
-	// create the actor path
+	host := "127.0.0.1"
 	ports := dynaport.Get(1)
-	actorPath := address.New("Test", "sys", "host", ports[0])
+
+	actorSystem, err := NewActorSystem("testSys",
+		WithRemoting(host, int32(ports[0])),
+		WithPassivationDisabled(),
+		WithJanitorInterval(time.Minute),
+		WithLogger(log.DiscardLogger))
+
+	require.NoError(t, err)
+	require.NotNil(t, actorSystem)
+
+	require.NoError(t, actorSystem.Start(ctx))
+
+	lib.Pause(time.Second)
 
 	// create the actor ref
-	pid, err := newPID(
-		ctx,
-		actorPath,
-		&exchanger{},
-		withInitMaxRetries(1),
-		withCustomLogger(log.DiscardLogger))
+	pid, err := actorSystem.Spawn(ctx, "Exchange1", &exchanger{})
 	require.NoError(t, err)
 	assert.NotNil(t, pid)
-	sys := pid.ActorSystem()
-	assert.Nil(t, sys)
 
-	expected := actorPath.Name()
+	expected := "Exchange1"
 	actual := pid.Name()
-
 	require.Equal(t, expected, actual)
 
 	// stop the actor
 	err = pid.Shutdown(ctx)
 	assert.NoError(t, err)
+	lib.Pause(time.Second)
+	assert.NoError(t, actorSystem.Stop(ctx))
 }
 func TestPipeTo(t *testing.T) {
 	t.Run("With happy path", func(t *testing.T) {
 		askTimeout := time.Minute
 		ctx := context.TODO()
-
-		opts := []pidOption{
-			withInitMaxRetries(1),
-			withPassivationDisabled(),
-			withCustomLogger(log.DiscardLogger),
-		}
+		host := "127.0.0.1"
 		ports := dynaport.Get(1)
 
+		actorSystem, err := NewActorSystem("testSys",
+			WithRemoting(host, int32(ports[0])),
+			WithPassivationDisabled(),
+			WithJanitorInterval(time.Minute),
+			WithLogger(log.DiscardLogger))
+
+		require.NoError(t, err)
+		require.NotNil(t, actorSystem)
+
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
+
 		// create actor1
-		actor1 := &exchanger{}
-		actorPath1 := address.New("Exchange1", "sys", "host", ports[0])
-		pid1, err := newPID(ctx, actorPath1, actor1, opts...)
+		pid1, err := actorSystem.Spawn(ctx, "Exchange1", &exchanger{})
 		require.NoError(t, err)
 		require.NotNil(t, pid1)
 
 		// create actor2
-		actor2 := &exchanger{}
-		actorPath2 := address.New("Exchange2", "sys", "host", ports[0])
-		pid2, err := newPID(ctx, actorPath2, actor2, opts...)
+		pid2, err := actorSystem.Spawn(ctx, "Exchange2", &exchanger{})
 		require.NoError(t, err)
 		require.NotNil(t, pid2)
 
@@ -2342,28 +2640,34 @@ func TestPipeTo(t *testing.T) {
 		lib.Pause(time.Second)
 		assert.NoError(t, pid1.Shutdown(ctx))
 		assert.NoError(t, pid2.Shutdown(ctx))
+		lib.Pause(time.Second)
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 	t.Run("With is a dead actor: case 1", func(t *testing.T) {
 		ctx := context.TODO()
-
-		opts := []pidOption{
-			withInitMaxRetries(1),
-			withPassivationDisabled(),
-			withCustomLogger(log.DiscardLogger),
-		}
+		host := "127.0.0.1"
 		ports := dynaport.Get(1)
 
+		actorSystem, err := NewActorSystem("testSys",
+			WithRemoting(host, int32(ports[0])),
+			WithPassivationDisabled(),
+			WithJanitorInterval(time.Minute),
+			WithLogger(log.DiscardLogger))
+
+		require.NoError(t, err)
+		require.NotNil(t, actorSystem)
+
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
+
 		// create actor1
-		actor1 := &exchanger{}
-		actorPath1 := address.New("Exchange1", "sys", "host", ports[0])
-		pid1, err := newPID(ctx, actorPath1, actor1, opts...)
+		pid1, err := actorSystem.Spawn(ctx, "Exchange1", &exchanger{})
 		require.NoError(t, err)
 		require.NotNil(t, pid1)
 
 		// create actor2
-		actor2 := &exchanger{}
-		actorPath2 := address.New("Exchange2", "sys", "host", ports[0])
-		pid2, err := newPID(ctx, actorPath2, actor2, opts...)
+		pid2, err := actorSystem.Spawn(ctx, "Exchange2", &exchanger{})
 		require.NoError(t, err)
 		require.NotNil(t, pid2)
 
@@ -2378,6 +2682,8 @@ func TestPipeTo(t *testing.T) {
 
 		lib.Pause(time.Second)
 		assert.NoError(t, pid1.Shutdown(ctx))
+		lib.Pause(time.Second)
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 	t.Run("With is a dead actor: case 2", func(t *testing.T) {
 		askTimeout := time.Minute
@@ -2439,25 +2745,29 @@ func TestPipeTo(t *testing.T) {
 	})
 	t.Run("With undefined task", func(t *testing.T) {
 		ctx := context.TODO()
-
-		opts := []pidOption{
-			withInitMaxRetries(1),
-			withPassivationDisabled(),
-			withCustomLogger(log.DiscardLogger),
-		}
+		host := "127.0.0.1"
 		ports := dynaport.Get(1)
 
+		actorSystem, err := NewActorSystem("testSys",
+			WithRemoting(host, int32(ports[0])),
+			WithPassivationDisabled(),
+			WithJanitorInterval(time.Minute),
+			WithLogger(log.DiscardLogger))
+
+		require.NoError(t, err)
+		require.NotNil(t, actorSystem)
+
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
+
 		// create actor1
-		actor1 := &exchanger{}
-		actorPath1 := address.New("Exchange1", "sys", "host", ports[0])
-		pid1, err := newPID(ctx, actorPath1, actor1, opts...)
+		pid1, err := actorSystem.Spawn(ctx, "Exchange1", &exchanger{})
 		require.NoError(t, err)
 		require.NotNil(t, pid1)
 
 		// create actor2
-		actor2 := &exchanger{}
-		actorPath2 := address.New("Exchange2", "sys", "host", ports[0])
-		pid2, err := newPID(ctx, actorPath2, actor2, opts...)
+		pid2, err := actorSystem.Spawn(ctx, "Exchange2", &exchanger{})
 		require.NoError(t, err)
 		require.NotNil(t, pid2)
 
@@ -2474,29 +2784,35 @@ func TestPipeTo(t *testing.T) {
 		lib.Pause(time.Second)
 		assert.NoError(t, pid1.Shutdown(ctx))
 		assert.NoError(t, pid2.Shutdown(ctx))
+		lib.Pause(time.Second)
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 	t.Run("With failed task", func(t *testing.T) {
 		askTimeout := time.Minute
 		ctx := context.TODO()
-
-		opts := []pidOption{
-			withInitMaxRetries(1),
-			withPassivationDisabled(),
-			withCustomLogger(log.DiscardLogger),
-		}
+		host := "127.0.0.1"
 		ports := dynaport.Get(1)
 
+		actorSystem, err := NewActorSystem("testSys",
+			WithRemoting(host, int32(ports[0])),
+			WithPassivationDisabled(),
+			WithJanitorInterval(time.Minute),
+			WithLogger(log.DiscardLogger))
+
+		require.NoError(t, err)
+		require.NotNil(t, actorSystem)
+
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
+
 		// create actor1
-		actor1 := &exchanger{}
-		actorPath1 := address.New("Exchange1", "sys", "host", ports[0])
-		pid1, err := newPID(ctx, actorPath1, actor1, opts...)
+		pid1, err := actorSystem.Spawn(ctx, "Exchange1", &exchanger{})
 		require.NoError(t, err)
 		require.NotNil(t, pid1)
 
 		// create actor2
-		actor2 := &exchanger{}
-		actorPath2 := address.New("Exchange2", "sys", "host", ports[0])
-		pid2, err := newPID(ctx, actorPath2, actor2, opts...)
+		pid2, err := actorSystem.Spawn(ctx, "Exchange2", &exchanger{})
 		require.NoError(t, err)
 		require.NotNil(t, pid2)
 
@@ -2537,6 +2853,8 @@ func TestPipeTo(t *testing.T) {
 		lib.Pause(time.Second)
 		assert.NoError(t, pid1.Shutdown(ctx))
 		assert.NoError(t, pid2.Shutdown(ctx))
+		lib.Pause(time.Second)
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 }
 func TestSendAsync(t *testing.T) {
@@ -2572,7 +2890,9 @@ func TestSendAsync(t *testing.T) {
 	})
 	t.Run("With dead Sender", func(t *testing.T) {
 		ctx := context.Background()
-		actorSystem, _ := NewActorSystem("testSys", WithLogger(log.DiscardLogger))
+		actorSystem, _ := NewActorSystem("testSys",
+			WithJanitorInterval(time.Minute),
+			WithLogger(log.DiscardLogger))
 
 		// start the actor system
 		err := actorSystem.Start(ctx)
@@ -2680,7 +3000,7 @@ func TestSendAsync(t *testing.T) {
 func TestSendSync(t *testing.T) {
 	t.Run("With local actor", func(t *testing.T) {
 		ctx := context.Background()
-		actorSystem, _ := NewActorSystem("testSys", WithLogger(log.DiscardLogger))
+		actorSystem, _ := NewActorSystem("testSys", WithLogger(log.DiscardLogger), WithJanitorInterval(time.Minute))
 
 		// start the actor system
 		err := actorSystem.Start(ctx)
@@ -2712,7 +3032,7 @@ func TestSendSync(t *testing.T) {
 	})
 	t.Run("With dead Sender", func(t *testing.T) {
 		ctx := context.Background()
-		actorSystem, _ := NewActorSystem("testSys", WithLogger(log.DiscardLogger))
+		actorSystem, _ := NewActorSystem("testSys", WithLogger(log.DiscardLogger), WithJanitorInterval(time.Minute))
 
 		// start the actor system
 		err := actorSystem.Start(ctx)
@@ -2823,18 +3143,24 @@ func TestSendSync(t *testing.T) {
 }
 func TestStopChild(t *testing.T) {
 	t.Run("With Stop failure", func(t *testing.T) {
-		// create a test context
 		ctx := context.TODO()
-		// create the actor path
+		host := "127.0.0.1"
 		ports := dynaport.Get(1)
-		actorPath := address.New("Test", "sys", "host", ports[0])
 
-		// create the parent actor
-		parent, err := newPID(ctx, actorPath,
-			newTestSupervisor(),
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger))
+		actorSystem, err := NewActorSystem("testSys",
+			WithRemoting(host, int32(ports[0])),
+			WithPassivationDisabled(),
+			WithJanitorInterval(time.Minute),
+			WithLogger(log.DiscardLogger))
 
+		require.NoError(t, err)
+		require.NotNil(t, actorSystem)
+
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
+
+		parent, err := actorSystem.Spawn(ctx, "parent", newTestSupervisor())
 		require.NoError(t, err)
 		require.NotNil(t, parent)
 
@@ -2849,6 +3175,8 @@ func TestStopChild(t *testing.T) {
 		//stop the actor
 		err = parent.Shutdown(ctx)
 		assert.NoError(t, err)
+		lib.Pause(time.Second)
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 }
 func TestNewPID(t *testing.T) {
diff --git a/actors/pid_tree_test.go b/actors/pid_tree_test.go
new file mode 100644
index 0000000..6ea2274
--- /dev/null
+++ b/actors/pid_tree_test.go
@@ -0,0 +1,99 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022-2024  Arsene Tochemey Gandote
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package actors
+
+import (
+	"sync"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+	"github.com/travisjeffery/go-dynaport"
+
+	"github.com/tochemey/goakt/v2/address"
+)
+
+func TestTree(t *testing.T) {
+	ports := dynaport.Get(1)
+	pid0 := &PID{address: address.New("pid0", "TestSys", "host", ports[0]), fieldsLocker: &sync.RWMutex{}, stopLocker: &sync.Mutex{}}
+	pid1 := &PID{address: address.New("pid1", "TestSys", "host", ports[0]), fieldsLocker: &sync.RWMutex{}, stopLocker: &sync.Mutex{}}
+	pid2 := &PID{address: address.New("pid2", "TestSys", "host", ports[0]), fieldsLocker: &sync.RWMutex{}, stopLocker: &sync.Mutex{}}
+	pid3 := &PID{address: address.New("pid3", "TestSys", "host", ports[0]), fieldsLocker: &sync.RWMutex{}, stopLocker: &sync.Mutex{}}
+	pid4 := &PID{address: address.New("pid4", "TestSys", "host", ports[0]), fieldsLocker: &sync.RWMutex{}, stopLocker: &sync.Mutex{}}
+	pid5 := &PID{address: address.New("pid5", "TestSys", "host", ports[0]), fieldsLocker: &sync.RWMutex{}, stopLocker: &sync.Mutex{}}
+
+	tree := newTree()
+
+	require.NoError(t, tree.AddNode(NoSender, pid0)) // pid0 has no parent
+	require.NoError(t, tree.AddNode(NoSender, pid1)) // pid1 has no parent
+	require.NoError(t, tree.AddNode(pid0, pid2))     // pid0 is parent of pid2
+	require.NoError(t, tree.AddNode(pid1, pid3))     // pid1 is parent of pid3
+	require.Error(t, tree.AddNode(pid4, pid5))       // this will error because pid4 does not exist on the tree
+	require.NoError(t, tree.AddNode(pid3, pid4))     // pid3 is parent of pid4
+
+	tree.AddWatcher(pid3, pid0)
+	tree.AddWatcher(pid4, pid5)
+
+	pid4Ancestors, ok := tree.Ancestors(pid4)
+	require.True(t, ok)
+	require.NotEmpty(t, pid4Ancestors)
+	require.Len(t, pid4Ancestors, 2)
+	pid4Parent, ok := tree.Parent(pid4)
+	require.True(t, ok)
+	require.NotNil(t, pid4Parent)
+	require.True(t, pid4Parent.GetValue().Equals(pid3))
+	pid4GParent, ok := tree.GrandParent(pid4)
+	require.True(t, ok)
+	require.True(t, pid4GParent.GetValue().Equals(pid1))
+	pid4GGParent, ok := tree.GreatGrandParent(pid4)
+	require.False(t, ok)
+	require.Nil(t, pid4GGParent)
+
+	require.EqualValues(t, 5, tree.Size())
+
+	node, ok := tree.GetNode(pid5.ID())
+	require.False(t, ok)
+	require.Nil(t, node)
+
+	tree.DeleteNode(pid1)
+	require.EqualValues(t, 2, tree.Size())
+	require.Len(t, tree.Nodes(), 2)
+
+	node, ok = tree.GetNode(pid1.ID())
+	require.False(t, ok)
+	require.Nil(t, node)
+
+	node, ok = tree.GetNode(pid3.ID())
+	require.False(t, ok)
+	require.Nil(t, node)
+
+	node, ok = tree.GetNode(pid4.ID())
+	require.False(t, ok)
+	require.Nil(t, node)
+
+	tree.Reset()
+	require.Empty(t, tree.Nodes())
+	assert.EqualValues(t, 0, tree.Size())
+}
diff --git a/actors/receive_context_test.go b/actors/receive_context_test.go
index 31cd361..0505c67 100644
--- a/actors/receive_context_test.go
+++ b/actors/receive_context_test.go
@@ -37,7 +37,6 @@ import (
 
 	"github.com/tochemey/goakt/v2/address"
 	"github.com/tochemey/goakt/v2/goaktpb"
-	"github.com/tochemey/goakt/v2/internal/eventstream"
 	"github.com/tochemey/goakt/v2/internal/lib"
 	"github.com/tochemey/goakt/v2/log"
 	"github.com/tochemey/goakt/v2/test/data/testpb"
@@ -47,19 +46,20 @@ import (
 func TestReceiveContext(t *testing.T) {
 	t.Run("With behaviors handling", func(t *testing.T) {
 		ctx := context.TODO()
-		// create the actor options
-		opts := []pidOption{
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger),
-		}
-
 		// create the actor path
 		actor := &behaviorQA{}
 		ports := dynaport.Get(1)
-		// create the actor path
-		actorPath := address.New("User", "sys", "host", ports[0])
 
-		pid, err := newPID(ctx, actorPath, actor, opts...)
+		actorSystem, err := NewActorSystem("sys",
+			WithRemoting("127.0.0.1", int32(ports[0])),
+			WithLogger(log.DiscardLogger))
+
+		require.NoError(t, err)
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
+
+		pid, err := actorSystem.Spawn(ctx, "User", actor)
 		require.NoError(t, err)
 		require.NotNil(t, pid)
 
@@ -105,21 +105,24 @@ func TestReceiveContext(t *testing.T) {
 
 		lib.Pause(time.Second)
 		assert.False(t, pid.IsRunning())
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 	t.Run("With successful Tell command", func(t *testing.T) {
 		ctx := context.TODO()
-		// create a Ping actor
-		opts := []pidOption{
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger),
-		}
-
 		ports := dynaport.Get(1)
 
+		actorSystem, err := NewActorSystem("sys",
+			WithRemoting("127.0.0.1", int32(ports[0])),
+			WithLogger(log.DiscardLogger))
+
+		require.NoError(t, err)
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
+
 		// create actor1
 		actor1 := &exchanger{}
-		actorPath1 := address.New("Exchange1", "sys", "host", ports[0])
-		pid1, err := newPID(ctx, actorPath1, actor1, opts...)
+		pid1, err := actorSystem.Spawn(ctx, "Exchange1", actor1)
 		require.NoError(t, err)
 		require.NotNil(t, pid1)
 
@@ -133,8 +136,7 @@ func TestReceiveContext(t *testing.T) {
 
 		// create actor2
 		actor2 := &exchanger{}
-		actorPath2 := address.New("Exchange2", "sys", "host", ports[0])
-		pid2, err := newPID(ctx, actorPath2, actor2, opts...)
+		pid2, err := actorSystem.Spawn(ctx, "Exchange2", actor2)
 		require.NoError(t, err)
 		require.NotNil(t, pid2)
 
@@ -142,21 +144,24 @@ func TestReceiveContext(t *testing.T) {
 		require.NoError(t, context.getError())
 
 		lib.Pause(time.Second)
-		assert.NoError(t, pid1.Shutdown(ctx))
-		assert.NoError(t, pid2.Shutdown(ctx))
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 	t.Run("With failed Tell", func(t *testing.T) {
 		ctx := context.TODO()
-		// create a Ping actor
-		opts := []pidOption{
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger),
-		}
 		ports := dynaport.Get(1)
+
+		actorSystem, err := NewActorSystem("sys",
+			WithRemoting("127.0.0.1", int32(ports[0])),
+			WithLogger(log.DiscardLogger))
+
+		require.NoError(t, err)
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
+
 		// create actor1
 		actor1 := &exchanger{}
-		actorPath1 := address.New("Exchange1", "sys", "host", ports[0])
-		pid1, err := newPID(ctx, actorPath1, actor1, opts...)
+		pid1, err := actorSystem.Spawn(ctx, "Exchange1", actor1)
 		require.NoError(t, err)
 		require.NotNil(t, pid1)
 
@@ -170,8 +175,7 @@ func TestReceiveContext(t *testing.T) {
 
 		// create actor2
 		actor2 := &exchanger{}
-		actorPath2 := address.New("Exchange2", "sys", "host", ports[0])
-		pid2, err := newPID(ctx, actorPath2, actor2, opts...)
+		pid2, err := actorSystem.Spawn(ctx, "Exchange2", actor2)
 		require.NoError(t, err)
 		require.NotNil(t, pid2)
 
@@ -182,20 +186,23 @@ func TestReceiveContext(t *testing.T) {
 		require.Error(t, context.getError())
 
 		lib.Pause(time.Second)
-		assert.NoError(t, pid1.Shutdown(ctx))
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 	t.Run("With successful Ask command", func(t *testing.T) {
 		ctx := context.TODO()
-		// create a Ping actor
-		opts := []pidOption{
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger),
-		}
 		ports := dynaport.Get(1)
+		actorSystem, err := NewActorSystem("sys",
+			WithRemoting("127.0.0.1", int32(ports[0])),
+			WithLogger(log.DiscardLogger))
+
+		require.NoError(t, err)
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
+
 		// create actor1
 		actor1 := &exchanger{}
-		actorPath1 := address.New("Exchange1", "sys", "host", ports[0])
-		pid1, err := newPID(ctx, actorPath1, actor1, opts...)
+		pid1, err := actorSystem.Spawn(ctx, "Exchange1", actor1)
 		require.NoError(t, err)
 		require.NotNil(t, pid1)
 
@@ -209,8 +216,7 @@ func TestReceiveContext(t *testing.T) {
 
 		// create actor2
 		actor2 := &exchanger{}
-		actorPath2 := address.New("Exchange2", "sys", "host", ports[0])
-		pid2, err := newPID(ctx, actorPath2, actor2, opts...)
+		pid2, err := actorSystem.Spawn(ctx, "Exchange2", actor2)
 		require.NoError(t, err)
 		require.NotNil(t, pid2)
 
@@ -220,21 +226,23 @@ func TestReceiveContext(t *testing.T) {
 		assert.True(t, proto.Equal(expected, reply))
 
 		lib.Pause(time.Second)
-		assert.NoError(t, pid1.Shutdown(ctx))
-		assert.NoError(t, pid2.Shutdown(ctx))
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 	t.Run("With failed Ask", func(t *testing.T) {
 		ctx := context.TODO()
-		// create a Ping actor
-		opts := []pidOption{
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger),
-		}
 		ports := dynaport.Get(1)
+		actorSystem, err := NewActorSystem("sys",
+			WithRemoting("127.0.0.1", int32(ports[0])),
+			WithLogger(log.DiscardLogger))
+
+		require.NoError(t, err)
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
+
 		// create actor1
 		actor1 := &exchanger{}
-		actorPath1 := address.New("Exchange1", "sys", "host", ports[0])
-		pid1, err := newPID(ctx, actorPath1, actor1, opts...)
+		pid1, err := actorSystem.Spawn(ctx, "Exchange1", actor1)
 		require.NoError(t, err)
 		require.NotNil(t, pid1)
 
@@ -248,8 +256,7 @@ func TestReceiveContext(t *testing.T) {
 
 		// create actor2
 		actor2 := &exchanger{}
-		actorPath2 := address.New("Exchange2", "sys", "host", ports[0])
-		pid2, err := newPID(ctx, actorPath2, actor2, opts...)
+		pid2, err := actorSystem.Spawn(ctx, "Exchange2", actor2)
 		require.NoError(t, err)
 		require.NotNil(t, pid2)
 
@@ -261,7 +268,7 @@ func TestReceiveContext(t *testing.T) {
 		require.Error(t, context.getError())
 
 		lib.Pause(time.Second)
-		assert.NoError(t, pid1.Shutdown(ctx))
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 	t.Run("With successful RemoteAsk", func(t *testing.T) {
 		// create the context
@@ -295,15 +302,7 @@ func TestReceiveContext(t *testing.T) {
 
 		// create actor1
 		actor1 := &exchanger{}
-		ports := dynaport.Get(1)
-		actorPath1 := address.New("Exchange1", "sys", "host", ports[0])
-		pid1, err := newPID(
-			ctx,
-			actorPath1,
-			actor1,
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger),
-		)
+		pid1, err := sys.Spawn(ctx, "Exchange1", actor1)
 		require.NoError(t, err)
 		require.NotNil(t, pid1)
 
@@ -361,15 +360,7 @@ func TestReceiveContext(t *testing.T) {
 
 		// create actor1
 		actor1 := &exchanger{}
-		ports := dynaport.Get(1)
-		actorPath1 := address.New("Exchange1", "sys", "host", ports[0])
-		pid1, err := newPID(
-			ctx,
-			actorPath1,
-			actor1,
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger),
-		)
+		pid1, err := sys.Spawn(ctx, "Exchange1", actor1)
 
 		require.NoError(t, err)
 		require.NotNil(t, pid1)
@@ -406,7 +397,7 @@ func TestReceiveContext(t *testing.T) {
 		// define the logger to use
 		logger := log.DiscardLogger
 		// generate the remoting port
-		nodePorts := dynaport.Get(1)
+		nodePorts := dynaport.Get(2)
 		remotingPort := nodePorts[0]
 		host := "127.0.0.1"
 
@@ -433,16 +424,16 @@ func TestReceiveContext(t *testing.T) {
 
 		// create actor1
 		actor1 := &exchanger{}
-		ports := dynaport.Get(1)
-		actorPath1 := address.New("Exchange1", "sys", "host", ports[0])
-		pid1, err := newPID(
-			ctx,
-			actorPath1,
-			actor1,
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger),
-		)
+		sys2, err := NewActorSystem("sys", WithLogger(logger),
+			WithPassivationDisabled(),
+			WithRemoting(host, int32(nodePorts[1])))
 
+		require.NoError(t, err)
+		require.NoError(t, sys2.Start(ctx))
+
+		lib.Pause(time.Second)
+
+		pid1, err := sys2.Spawn(ctx, "Exchange1", actor1)
 		require.NoError(t, err)
 		require.NotNil(t, pid1)
 
@@ -465,6 +456,7 @@ func TestReceiveContext(t *testing.T) {
 			func() {
 				assert.NoError(t, pid1.Shutdown(ctx))
 				assert.NoError(t, sys.Stop(ctx))
+				assert.NoError(t, sys2.Stop(ctx))
 			},
 		)
 	})
@@ -498,15 +490,12 @@ func TestReceiveContext(t *testing.T) {
 		// create actor1
 		actor1 := &exchanger{}
 		ports := dynaport.Get(1)
-		actorPath1 := address.New("Exchange1", "sys", "host", ports[0])
-		pid1, err := newPID(
-			ctx,
-			actorPath1,
-			actor1,
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger),
-		)
+		sys2, err := NewActorSystem("sys", WithLogger(logger), WithRemoting(host, int32(ports[0])))
+		require.NoError(t, err)
+		require.NoError(t, sys2.Start(ctx))
+		lib.Pause(time.Second)
 
+		pid1, err := sys2.Spawn(ctx, "Exchange1", actor1)
 		require.NoError(t, err)
 		require.NotNil(t, pid1)
 
@@ -534,6 +523,7 @@ func TestReceiveContext(t *testing.T) {
 			func() {
 				assert.NoError(t, pid1.Shutdown(ctx))
 				assert.NoError(t, sys.Stop(ctx))
+				assert.NoError(t, sys2.Stop(ctx))
 			},
 		)
 	})
@@ -567,15 +557,12 @@ func TestReceiveContext(t *testing.T) {
 		// create actor1
 		actor1 := &exchanger{}
 		ports := dynaport.Get(1)
-		actorPath1 := address.New("Exchange1", "sys", "host", ports[0])
-		pid1, err := newPID(
-			ctx,
-			actorPath1,
-			actor1,
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger),
-		)
+		sys2, err := NewActorSystem("sys", WithLogger(logger), WithRemoting(host, int32(ports[0])))
+		require.NoError(t, err)
+		require.NoError(t, sys2.Start(ctx))
+		lib.Pause(time.Second)
 
+		pid1, err := sys2.Spawn(ctx, "Exchange1", actor1)
 		require.NoError(t, err)
 		require.NotNil(t, pid1)
 
@@ -595,6 +582,7 @@ func TestReceiveContext(t *testing.T) {
 			func() {
 				assert.NoError(t, pid1.Shutdown(ctx))
 				assert.NoError(t, sys.Stop(ctx))
+				assert.NoError(t, sys2.Stop(ctx))
 			},
 		)
 	})
@@ -627,14 +615,15 @@ func TestReceiveContext(t *testing.T) {
 		// create actor1
 		actor1 := &exchanger{}
 		ports := dynaport.Get(1)
-		actorPath1 := address.New("Exchange1", "sys", "host", ports[0])
-		pid1, err := newPID(
-			ctx,
-			actorPath1,
-			actor1,
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger),
-		)
+
+		sys2, err := NewActorSystem("sys", WithLogger(logger), WithRemoting(host, int32(ports[0])))
+		require.NoError(t, err)
+		require.NoError(t, sys2.Start(ctx))
+		lib.Pause(time.Second)
+
+		pid1, err := sys2.Spawn(ctx, "Exchange1", actor1)
+		require.NoError(t, err)
+		require.NotNil(t, pid1)
 
 		require.NoError(t, err)
 		require.NotNil(t, pid1)
@@ -654,22 +643,25 @@ func TestReceiveContext(t *testing.T) {
 			func() {
 				assert.NoError(t, pid1.Shutdown(ctx))
 				assert.NoError(t, sys.Stop(ctx))
+				assert.NoError(t, sys2.Stop(ctx))
 			},
 		)
 	})
 	t.Run("With successful Shutdown", func(t *testing.T) {
 		ctx := context.TODO()
-		// create a Ping actor
-		opts := []pidOption{
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger),
-		}
+		ports := dynaport.Get(1)
+		actorSystem, err := NewActorSystem("sys",
+			WithRemoting("127.0.0.1", int32(ports[0])),
+			WithLogger(log.DiscardLogger))
+
+		require.NoError(t, err)
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
 
 		// create actor1
 		actor1 := &exchanger{}
-		ports := dynaport.Get(1)
-		actorPath1 := address.New("Exchange1", "sys", "host", ports[0])
-		pid1, err := newPID(ctx, actorPath1, actor1, opts...)
+		pid1, err := actorSystem.Spawn(ctx, "Exchange1", actor1)
 
 		require.NoError(t, err)
 		require.NotNil(t, pid1)
@@ -684,23 +676,27 @@ func TestReceiveContext(t *testing.T) {
 
 		context.Shutdown()
 		require.NoError(t, context.getError())
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 	t.Run("With successful SpawnChild", func(t *testing.T) {
 		ctx := context.TODO()
 		ports := dynaport.Get(1)
-		actorPath := address.New("Parent", "sys", "host", ports[0])
+		actorSystem, err := NewActorSystem("sys",
+			WithRemoting("127.0.0.1", int32(ports[0])),
+			WithLogger(log.DiscardLogger))
 
-		// create the parent actor
-		parent, err := newPID(
-			ctx, actorPath,
-			newTestSupervisor(),
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger),
-		)
+		require.NoError(t, err)
+		require.NoError(t, actorSystem.Start(ctx))
 
+		lib.Pause(time.Second)
+
+		// create the parent actor
+		parent, err := actorSystem.Spawn(ctx, "Parent", newTestSupervisor())
 		require.NoError(t, err)
 		assert.NotNil(t, parent)
 
+		lib.Pause(time.Second)
+
 		// create an instance of receive receiveCtx
 		receiveCtx := &ReceiveContext{
 			ctx:     ctx,
@@ -722,21 +718,29 @@ func TestReceiveContext(t *testing.T) {
 		t.Cleanup(
 			func() {
 				receiveCtx.Shutdown()
+				assert.NoError(t, actorSystem.Stop(ctx))
 			},
 		)
 	})
 	t.Run("With failed SpawnChild", func(t *testing.T) {
 		ctx := context.TODO()
 		ports := dynaport.Get(1)
-		actorPath := address.New("Parent", "sys", "host", ports[0])
+
+		actorSystem, err := NewActorSystem("sys",
+			WithRemoting("127.0.0.1", int32(ports[0])),
+			WithLogger(log.DiscardLogger))
+
+		require.NoError(t, err)
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
 
 		// create the parent actor
-		parent, err := newPID(
-			ctx, actorPath,
-			newTestSupervisor(),
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger),
-		)
+		parent, err := actorSystem.Spawn(ctx, "Parent", newTestSupervisor())
+		require.NoError(t, err)
+		assert.NotNil(t, parent)
+
+		lib.Pause(time.Second)
 
 		require.NoError(t, err)
 		assert.NotNil(t, parent)
@@ -755,20 +759,23 @@ func TestReceiveContext(t *testing.T) {
 		// create the child actor
 		context.Spawn("SpawnChild", newTestSupervised())
 		require.Error(t, context.getError())
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 	t.Run("With not found Child", func(t *testing.T) {
 		ctx := context.TODO()
 		ports := dynaport.Get(1)
-		actorPath := address.New("Parent", "sys", "host", ports[0])
 
-		// create the parent actor
-		parent, err := newPID(
-			ctx, actorPath,
-			newTestSupervisor(),
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger),
-		)
+		actorSystem, err := NewActorSystem("sys",
+			WithRemoting("127.0.0.1", int32(ports[0])),
+			WithLogger(log.DiscardLogger))
 
+		require.NoError(t, err)
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
+
+		// create the parent actor
+		parent, err := actorSystem.Spawn(ctx, "Parent", newTestSupervisor())
 		require.NoError(t, err)
 		assert.NotNil(t, parent)
 
@@ -794,21 +801,24 @@ func TestReceiveContext(t *testing.T) {
 		t.Cleanup(
 			func() {
 				context.Shutdown()
+				assert.NoError(t, actorSystem.Stop(ctx))
 			},
 		)
 	})
 	t.Run("With dead parent Child", func(t *testing.T) {
 		ctx := context.TODO()
 		ports := dynaport.Get(1)
-		actorPath := address.New("Parent", "sys", "host", ports[0])
+		actorSystem, err := NewActorSystem("sys",
+			WithRemoting("127.0.0.1", int32(ports[0])),
+			WithLogger(log.DiscardLogger))
+
+		require.NoError(t, err)
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
 
 		// create the parent actor
-		parent, err := newPID(
-			ctx, actorPath,
-			newTestSupervisor(),
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger),
-		)
+		parent, err := actorSystem.Spawn(ctx, "Parent", newTestSupervisor())
 
 		require.NoError(t, err)
 		assert.NotNil(t, parent)
@@ -835,21 +845,22 @@ func TestReceiveContext(t *testing.T) {
 		t.Cleanup(
 			func() {
 				require.NoError(t, child.Shutdown(ctx))
+				assert.NoError(t, actorSystem.Stop(ctx))
 			},
 		)
 	})
 	t.Run("With successful Stop", func(t *testing.T) {
 		ctx := context.TODO()
 		ports := dynaport.Get(1)
-		actorPath := address.New("Parent", "sys", "host", ports[0])
+		actorSystem, err := NewActorSystem("sys",
+			WithRemoting("127.0.0.1", int32(ports[0])),
+			WithLogger(log.DiscardLogger))
 
-		// create the parent actor
-		parent, err := newPID(
-			ctx, actorPath,
-			newTestSupervisor(),
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger),
-		)
+		require.NoError(t, err)
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
+		parent, err := actorSystem.Spawn(ctx, "Parent", newTestSupervisor())
 
 		require.NoError(t, err)
 		assert.NotNil(t, parent)
@@ -876,21 +887,23 @@ func TestReceiveContext(t *testing.T) {
 		t.Cleanup(
 			func() {
 				context.Shutdown()
+				assert.NoError(t, actorSystem.Stop(ctx))
 			},
 		)
 	})
 	t.Run("With child actor Stop freeing up parent link", func(t *testing.T) {
 		ctx := context.TODO()
 		ports := dynaport.Get(1)
-		actorPath := address.New("Parent", "sys", "host", ports[0])
+		actorSystem, err := NewActorSystem("sys",
+			WithRemoting("127.0.0.1", int32(ports[0])),
+			WithLogger(log.DiscardLogger))
 
-		// create the parent actor
-		parent, err := newPID(
-			ctx, actorPath,
-			newTestSupervisor(),
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger),
-		)
+		require.NoError(t, err)
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
+
+		parent, err := actorSystem.Spawn(ctx, "Parent", newTestSupervisor())
 
 		require.NoError(t, err)
 		assert.NotNil(t, parent)
@@ -921,21 +934,23 @@ func TestReceiveContext(t *testing.T) {
 		t.Cleanup(
 			func() {
 				context.Shutdown()
+				assert.NoError(t, actorSystem.Stop(ctx))
 			},
 		)
 	})
 	t.Run("With failed Stop: child not defined", func(t *testing.T) {
 		ctx := context.TODO()
 		ports := dynaport.Get(1)
-		actorPath := address.New("Parent", "sys", "host", ports[0])
+		actorSystem, err := NewActorSystem("sys",
+			WithRemoting("127.0.0.1", int32(ports[0])),
+			WithLogger(log.DiscardLogger))
 
-		// create the parent actor
-		parent, err := newPID(
-			ctx, actorPath,
-			newTestSupervisor(),
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger),
-		)
+		require.NoError(t, err)
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
+
+		parent, err := actorSystem.Spawn(ctx, "Parent", newTestSupervisor())
 
 		require.NoError(t, err)
 		assert.NotNil(t, parent)
@@ -955,22 +970,23 @@ func TestReceiveContext(t *testing.T) {
 		t.Cleanup(
 			func() {
 				context.Shutdown()
+				assert.NoError(t, actorSystem.Stop(ctx))
 			},
 		)
 	})
 	t.Run("With failed Stop: parent is dead", func(t *testing.T) {
 		ctx := context.TODO()
 		ports := dynaport.Get(1)
-		// create the actor path
-		actorPath := address.New("Test", "sys", "host", ports[0])
+		actorSystem, err := NewActorSystem("sys",
+			WithRemoting("127.0.0.1", int32(ports[0])),
+			WithLogger(log.DiscardLogger))
 
-		// create the parent actor
-		parent, err := newPID(
-			ctx, actorPath,
-			newTestSupervisor(),
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger),
-		)
+		require.NoError(t, err)
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
+
+		parent, err := actorSystem.Spawn(ctx, "Parent", newTestSupervisor())
 
 		require.NoError(t, err)
 		assert.NotNil(t, parent)
@@ -997,20 +1013,21 @@ func TestReceiveContext(t *testing.T) {
 		// stop the child actor
 		context.Stop(child)
 		require.Error(t, context.getError())
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 	t.Run("With failed Stop: actor not found", func(t *testing.T) {
 		ctx := context.TODO()
 		ports := dynaport.Get(1)
-		actorPath := address.New("Parent", "sys", "host", ports[0])
+		actorSystem, err := NewActorSystem("sys",
+			WithRemoting("127.0.0.1", int32(ports[0])),
+			WithLogger(log.DiscardLogger))
 
-		// create the parent actor
-		parent, err := newPID(
-			ctx, actorPath,
-			newTestSupervisor(),
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger),
-		)
+		require.NoError(t, err)
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
 
+		parent, err := actorSystem.Spawn(ctx, "Parent", newTestSupervisor())
 		require.NoError(t, err)
 		assert.NotNil(t, parent)
 
@@ -1023,11 +1040,12 @@ func TestReceiveContext(t *testing.T) {
 		}
 
 		// create the child actor
-		childPath := address.New("child", "sys", "host", ports[0])
+		childPath := address.New("child", "sys", "127.0.0.1", ports[0])
 		child, err := newPID(
 			ctx, childPath,
 			newTestSupervisor(),
 			withInitMaxRetries(1),
+			withActorSystem(actorSystem),
 			withCustomLogger(log.DiscardLogger),
 		)
 
@@ -1040,21 +1058,23 @@ func TestReceiveContext(t *testing.T) {
 			func() {
 				context.Shutdown()
 				assert.NoError(t, child.Shutdown(ctx))
+				assert.NoError(t, actorSystem.Stop(ctx))
 			},
 		)
 	})
 	t.Run("With Stop when child is already stopped", func(t *testing.T) {
 		ctx := context.TODO()
 		ports := dynaport.Get(1)
-		actorPath := address.New("Parent", "sys", "host", ports[0])
+		actorSystem, err := NewActorSystem("sys",
+			WithRemoting("127.0.0.1", int32(ports[0])),
+			WithLogger(log.DiscardLogger))
 
-		// create the parent actor
-		parent, err := newPID(
-			ctx, actorPath,
-			newTestSupervisor(),
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger),
-		)
+		require.NoError(t, err)
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
+
+		parent, err := actorSystem.Spawn(ctx, "Parent", newTestSupervisor())
 
 		require.NoError(t, err)
 		assert.NotNil(t, parent)
@@ -1083,23 +1103,25 @@ func TestReceiveContext(t *testing.T) {
 		t.Cleanup(
 			func() {
 				context.Shutdown()
+				assert.NoError(t, actorSystem.Stop(ctx))
 			},
 		)
 	})
 	t.Run("With failed Shutdown", func(t *testing.T) {
 		ctx := context.TODO()
-		// create a Ping actor
-		opts := []pidOption{
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger),
-		}
-
 		ports := dynaport.Get(1)
+		actorSystem, err := NewActorSystem("sys",
+			WithRemoting("127.0.0.1", int32(ports[0])),
+			WithLogger(log.DiscardLogger))
+
+		require.NoError(t, err)
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
 
 		// create actor1
 		actor1 := &postStopQA{}
-		actorPath1 := address.New("Exchange1", "sys", "host", ports[0])
-		pid1, err := newPID(ctx, actorPath1, actor1, opts...)
+		pid1, err := actorSystem.Spawn(ctx, "Exchange1", actor1)
 		require.NoError(t, err)
 		require.NotNil(t, pid1)
 
@@ -1113,28 +1135,30 @@ func TestReceiveContext(t *testing.T) {
 
 		context.Shutdown()
 		require.Error(t, context.getError())
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 	t.Run("With successful Forward", func(t *testing.T) {
 		ctx := context.TODO()
-		// create a Ping actor
-		opts := []pidOption{
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger),
-		}
-
 		ports := dynaport.Get(1)
 
+		actorSystem, err := NewActorSystem("sys",
+			WithRemoting("127.0.0.1", int32(ports[0])),
+			WithLogger(log.DiscardLogger))
+
+		require.NoError(t, err)
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
+
 		// create actorA
 		actorA := &exchanger{}
-		actorPath1 := address.New("actorA", "sys", "host", ports[0])
-		pidA, err := newPID(ctx, actorPath1, actorA, opts...)
+		pidA, err := actorSystem.Spawn(ctx, "actorA", actorA)
 		require.NoError(t, err)
 		require.NotNil(t, pidA)
 
 		// create actorC
 		actorC := &exchanger{}
-		actorPath3 := address.New("actorC", "sys", "host", ports[0])
-		pidC, err := newPID(ctx, actorPath3, actorC, opts...)
+		pidC, err := actorSystem.Spawn(ctx, "actorC", actorC)
 		require.NoError(t, err)
 		require.NotNil(t, pidC)
 
@@ -1142,8 +1166,8 @@ func TestReceiveContext(t *testing.T) {
 		actorB := &forwardQA{
 			actorRef: pidC,
 		}
-		actorPath2 := address.New("actorB", "sys", "host", ports[0])
-		pidB, err := newPID(ctx, actorPath2, actorB, opts...)
+
+		pidB, err := actorSystem.Spawn(ctx, "actorB", actorB)
 		require.NoError(t, err)
 		require.NotNil(t, pidB)
 
@@ -1162,30 +1186,27 @@ func TestReceiveContext(t *testing.T) {
 		// let us shutdown the rest
 		require.NoError(t, pidA.Shutdown(ctx))
 		require.NoError(t, pidB.Shutdown(ctx))
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 	t.Run("With Unhandled with no sender", func(t *testing.T) {
 		ctx := context.TODO()
-		// create the deadletter stream
-		eventsStream := eventstream.New()
+		ports := dynaport.Get(1)
+		actorSystem, err := NewActorSystem("sys",
+			WithRemoting("127.0.0.1", int32(ports[0])),
+			WithLogger(log.DiscardLogger))
 
-		// create a consumer
-		consumer := eventsStream.AddSubscriber()
-		eventsStream.Subscribe(consumer, eventsTopic)
+		require.NoError(t, err)
+		require.NoError(t, actorSystem.Start(ctx))
 
-		// create a Ping actor
-		opts := []pidOption{
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger),
-			withEventsStream(eventsStream),
-		}
+		lib.Pause(time.Second)
 
-		ports := dynaport.Get(1)
+		// create a consumer
+		consumer, err := actorSystem.Subscribe()
+		require.NoError(t, err)
 
 		// create actor1
 		actor1 := &exchanger{}
-		actorPath1 := address.New("Exchange1", "sys", "host", ports[0])
-		pid1, err := newPID(ctx, actorPath1, actor1, opts...)
-
+		pid1, err := actorSystem.Spawn(ctx, "Exchange1", actor1)
 		require.NoError(t, err)
 		require.NotNil(t, pid1)
 
@@ -1230,38 +1251,36 @@ func TestReceiveContext(t *testing.T) {
 				// shutdown the consumer
 				consumer.Shutdown()
 				context.Shutdown()
+				assert.NoError(t, actorSystem.Stop(ctx))
 			},
 		)
 	})
 	t.Run("With Unhandled with a sender", func(t *testing.T) {
 		ctx := context.TODO()
-		// create the deadletter stream
-		eventsStream := eventstream.New()
+		ports := dynaport.Get(1)
 
-		// create a consumer
-		consumer := eventsStream.AddSubscriber()
-		eventsStream.Subscribe(consumer, eventsTopic)
+		actorSystem, err := NewActorSystem("sys",
+			WithRemoting("127.0.0.1", int32(ports[0])),
+			WithLogger(log.DiscardLogger))
 
-		// create a Ping actor
-		opts := []pidOption{
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger),
-			withEventsStream(eventsStream),
-		}
+		require.NoError(t, err)
+		require.NoError(t, actorSystem.Start(ctx))
 
-		ports := dynaport.Get(1)
+		lib.Pause(time.Second)
+
+		// create a consumer
+		consumer, err := actorSystem.Subscribe()
+		require.NoError(t, err)
 
 		// create actor1
 		actor1 := &exchanger{}
-		actorPath1 := address.New("Exchange1", "sys", "host", ports[0])
-		pid1, err := newPID(ctx, actorPath1, actor1, opts...)
+		pid1, err := actorSystem.Spawn(ctx, "Exchange1", actor1)
 
 		require.NoError(t, err)
 		require.NotNil(t, pid1)
 
 		actor2 := &exchanger{}
-		actorPath2 := address.New("Exchange2", "sys", "host", ports[0])
-		pid2, err := newPID(ctx, actorPath2, actor2, opts...)
+		pid2, err := actorSystem.Spawn(ctx, "Exchange2", actor2)
 
 		send := new(testpb.TestSend)
 		// create an instance of receive context
@@ -1294,7 +1313,7 @@ func TestReceiveContext(t *testing.T) {
 		require.NoError(t, msg.UnmarshalTo(actual))
 		require.True(t, proto.Equal(send, actual))
 		require.Equal(t, deadletter.GetReason(), ErrUnhandled.Error())
-		assert.True(t, proto.Equal(deadletter.GetSender(), actorPath2.Address))
+		assert.True(t, proto.Equal(deadletter.GetSender(), pid2.Address().Address))
 
 		assert.EqualValues(t, 1, len(consumer.Topics()))
 
@@ -1304,31 +1323,30 @@ func TestReceiveContext(t *testing.T) {
 				// shutdown the consumer
 				consumer.Shutdown()
 				context.Shutdown()
+				assert.NoError(t, actorSystem.Stop(ctx))
 			},
 		)
 	})
 	t.Run("With Unhandled with system messages", func(t *testing.T) {
 		ctx := context.TODO()
-		// create the deadletter stream
-		eventsStream := eventstream.New()
+		ports := dynaport.Get(1)
 
-		// create a consumer
-		consumer := eventsStream.AddSubscriber()
-		eventsStream.Subscribe(consumer, eventsTopic)
+		actorSystem, err := NewActorSystem("sys",
+			WithRemoting("127.0.0.1", int32(ports[0])),
+			WithLogger(log.DiscardLogger))
 
-		// create a Ping actor
-		opts := []pidOption{
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger),
-			withEventsStream(eventsStream),
-		}
+		require.NoError(t, err)
+		require.NoError(t, actorSystem.Start(ctx))
 
-		ports := dynaport.Get(1)
+		lib.Pause(time.Second)
+
+		// create a consumer
+		consumer, err := actorSystem.Subscribe()
+		require.NoError(t, err)
 
 		// create actor1
 		actor1 := &exchanger{}
-		actorPath1 := address.New("Exchange1", "sys", "host", ports[0])
-		pid1, err := newPID(ctx, actorPath1, actor1, opts...)
+		pid1, err := actorSystem.Spawn(ctx, "Exchange1", actor1)
 
 		require.NoError(t, err)
 		require.NotNil(t, pid1)
@@ -1366,23 +1384,26 @@ func TestReceiveContext(t *testing.T) {
 				// shutdown the consumer
 				consumer.Shutdown()
 				context.Shutdown()
+				assert.NoError(t, actorSystem.Stop(ctx))
 			},
 		)
 	})
 	t.Run("With successful BatchTell", func(t *testing.T) {
 		ctx := context.TODO()
-		// create a Ping actor
-		opts := []pidOption{
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger),
-		}
-
 		ports := dynaport.Get(1)
 
+		actorSystem, err := NewActorSystem("sys",
+			WithRemoting("127.0.0.1", int32(ports[0])),
+			WithLogger(log.DiscardLogger))
+
+		require.NoError(t, err)
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
+
 		// create actor1
 		actor1 := &exchanger{}
-		actorPath1 := address.New("Exchange1", "sys", "host", ports[0])
-		pid1, err := newPID(ctx, actorPath1, actor1, opts...)
+		pid1, err := actorSystem.Spawn(ctx, "Exchange1", actor1)
 		require.NoError(t, err)
 		require.NotNil(t, pid1)
 
@@ -1396,8 +1417,7 @@ func TestReceiveContext(t *testing.T) {
 
 		// create actor2
 		actor2 := &exchanger{}
-		actorPath2 := address.New("Exchange2", "sys", "host", ports[0])
-		pid2, err := newPID(ctx, actorPath2, actor2, opts...)
+		pid2, err := actorSystem.Spawn(ctx, "Exchange2", actor2)
 		require.NoError(t, err)
 		require.NotNil(t, pid2)
 
@@ -1407,21 +1427,25 @@ func TestReceiveContext(t *testing.T) {
 		lib.Pause(time.Second)
 		assert.NoError(t, pid1.Shutdown(ctx))
 		assert.NoError(t, pid2.Shutdown(ctx))
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 	t.Run("With successful BatchTell as a Tell", func(t *testing.T) {
 		ctx := context.TODO()
-		// create a Ping actor
-		opts := []pidOption{
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger),
-		}
-
 		ports := dynaport.Get(1)
 
+		actorSystem, err := NewActorSystem("sys",
+			WithRemoting("127.0.0.1", int32(ports[0])),
+			WithLogger(log.DiscardLogger))
+
+		require.NoError(t, err)
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
+
 		// create actor1
 		actor1 := &exchanger{}
-		actorPath1 := address.New("Exchange1", "sys", "host", ports[0])
-		pid1, err := newPID(ctx, actorPath1, actor1, opts...)
+
+		pid1, err := actorSystem.Spawn(ctx, "Exchange1", actor1)
 		require.NoError(t, err)
 		require.NotNil(t, pid1)
 
@@ -1435,8 +1459,7 @@ func TestReceiveContext(t *testing.T) {
 
 		// create actor2
 		actor2 := &exchanger{}
-		actorPath2 := address.New("Exchange2", "sys", "host", ports[0])
-		pid2, err := newPID(ctx, actorPath2, actor2, opts...)
+		pid2, err := actorSystem.Spawn(ctx, "Exchange2", actor2)
 		require.NoError(t, err)
 		require.NotNil(t, pid2)
 
@@ -1446,21 +1469,24 @@ func TestReceiveContext(t *testing.T) {
 		lib.Pause(time.Second)
 		assert.NoError(t, pid1.Shutdown(ctx))
 		assert.NoError(t, pid2.Shutdown(ctx))
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 	t.Run("With failed BatchTell", func(t *testing.T) {
 		ctx := context.TODO()
-		// create a Ping actor
-		opts := []pidOption{
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger),
-		}
-
 		ports := dynaport.Get(1)
 
+		actorSystem, err := NewActorSystem("sys",
+			WithRemoting("127.0.0.1", int32(ports[0])),
+			WithLogger(log.DiscardLogger))
+
+		require.NoError(t, err)
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
+
 		// create actor1
 		actor1 := &exchanger{}
-		actorPath1 := address.New("Exchange1", "sys", "host", ports[0])
-		pid1, err := newPID(ctx, actorPath1, actor1, opts...)
+		pid1, err := actorSystem.Spawn(ctx, "Exchange1", actor1)
 		require.NoError(t, err)
 		require.NotNil(t, pid1)
 
@@ -1474,8 +1500,7 @@ func TestReceiveContext(t *testing.T) {
 
 		// create actor2
 		actor2 := &exchanger{}
-		actorPath2 := address.New("Exchange2", "sys", "host", ports[0])
-		pid2, err := newPID(ctx, actorPath2, actor2, opts...)
+		pid2, err := actorSystem.Spawn(ctx, "Exchange2", actor2)
 		require.NoError(t, err)
 		require.NotNil(t, pid2)
 
@@ -1488,21 +1513,24 @@ func TestReceiveContext(t *testing.T) {
 
 		lib.Pause(time.Second)
 		assert.NoError(t, pid1.Shutdown(ctx))
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 	t.Run("With successful BatchAsk", func(t *testing.T) {
 		ctx := context.TODO()
-		// create a Ping actor
-		opts := []pidOption{
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger),
-		}
-
 		ports := dynaport.Get(1)
 
+		actorSystem, err := NewActorSystem("sys",
+			WithRemoting("127.0.0.1", int32(ports[0])),
+			WithLogger(log.DiscardLogger))
+
+		require.NoError(t, err)
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
+
 		// create actor1
 		actor1 := &exchanger{}
-		actorPath1 := address.New("Exchange1", "sys", "host", ports[0])
-		pid1, err := newPID(ctx, actorPath1, actor1, opts...)
+		pid1, err := actorSystem.Spawn(ctx, "Exchange1", actor1)
 		require.NoError(t, err)
 		require.NotNil(t, pid1)
 
@@ -1516,8 +1544,7 @@ func TestReceiveContext(t *testing.T) {
 
 		// create actor2
 		actor2 := &exchanger{}
-		actorPath2 := address.New("Exchange2", "sys", "host", ports[0])
-		pid2, err := newPID(ctx, actorPath2, actor2, opts...)
+		pid2, err := actorSystem.Spawn(ctx, "Exchange2", actor2)
 		require.NoError(t, err)
 		require.NotNil(t, pid2)
 
@@ -1532,21 +1559,25 @@ func TestReceiveContext(t *testing.T) {
 		lib.Pause(time.Second)
 		assert.NoError(t, pid1.Shutdown(ctx))
 		assert.NoError(t, pid2.Shutdown(ctx))
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 	t.Run("With failed BatchAsk", func(t *testing.T) {
 		ctx := context.TODO()
-		// create a Ping actor
-		opts := []pidOption{
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger),
-		}
-
 		ports := dynaport.Get(1)
 
+		actorSystem, err := NewActorSystem("sys",
+			WithRemoting("127.0.0.1", int32(ports[0])),
+			WithLogger(log.DiscardLogger))
+
+		require.NoError(t, err)
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
+
 		// create actor1
 		actor1 := &exchanger{}
-		actorPath1 := address.New("Exchange1", "sys", "host", ports[0])
-		pid1, err := newPID(ctx, actorPath1, actor1, opts...)
+
+		pid1, err := actorSystem.Spawn(ctx, "Exchange1", actor1)
 		require.NoError(t, err)
 		require.NotNil(t, pid1)
 
@@ -1560,8 +1591,7 @@ func TestReceiveContext(t *testing.T) {
 
 		// create actor2
 		actor2 := &exchanger{}
-		actorPath2 := address.New("Exchange2", "sys", "host", ports[0])
-		pid2, err := newPID(ctx, actorPath2, actor2, opts...)
+		pid2, err := actorSystem.Spawn(ctx, "Exchange2", actor2)
 		require.NoError(t, err)
 		require.NotNil(t, pid2)
 
@@ -1574,6 +1604,7 @@ func TestReceiveContext(t *testing.T) {
 
 		lib.Pause(time.Second)
 		assert.NoError(t, pid1.Shutdown(ctx))
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 	t.Run("With successful RemoteBatchTell", func(t *testing.T) {
 		// create the context
@@ -1770,16 +1801,8 @@ func TestReceiveContext(t *testing.T) {
 		actorName2 := "Exchange2"
 
 		// create actor1
-		ports := dynaport.Get(1)
 		actor1 := &exchanger{}
-		actorPath1 := address.New("Exchange1", "sys", "host", ports[0])
-		pid1, err := newPID(
-			ctx,
-			actorPath1,
-			actor1,
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger),
-		)
+		pid1, err := sys.Spawn(ctx, "Exchange1", actor1)
 
 		require.NoError(t, err)
 		require.NotNil(t, pid1)
@@ -1898,17 +1921,8 @@ func TestReceiveContext(t *testing.T) {
 		actorName2 := "Exchange2"
 
 		// create actor1
-		ports := dynaport.Get(1)
 		actor1 := &exchanger{}
-		actorPath1 := address.New("Exchange1", "sys", "host", ports[0])
-		pid1, err := newPID(
-			ctx,
-			actorPath1,
-			actor1,
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger),
-		)
-
+		pid1, err := sys.Spawn(ctx, "Exchange1", actor1)
 		require.NoError(t, err)
 		require.NotNil(t, pid1)
 
@@ -1966,17 +1980,10 @@ func TestReceiveContext(t *testing.T) {
 		actorName2 := "Exchange2"
 
 		// create actor1
-		ports := dynaport.Get(1)
 		actor1 := &exchanger{}
-		actorPath1 := address.New("Exchange1", "sys", "host", ports[0])
-		pid1, err := newPID(
-			ctx,
-			actorPath1,
-			actor1,
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger),
-		)
-
+		pid1, err := sys.Spawn(ctx, "Exchange1", actor1)
+		require.NoError(t, err)
+		require.NotNil(t, pid1)
 		require.NoError(t, err)
 		require.NotNil(t, pid1)
 
@@ -2022,21 +2029,12 @@ func TestReceiveContext(t *testing.T) {
 		err = sys.Start(ctx)
 		assert.NoError(t, err)
 
-		// create an exchanger two
+		// create an exchanger 2
 		actorName2 := "Exchange2"
 
 		// create actor1
 		actor1 := &exchanger{}
-		ports := dynaport.Get(1)
-		actorPath1 := address.New("Exchange1", "sys", "host", ports[0])
-		pid1, err := newPID(
-			ctx,
-			actorPath1,
-			actor1,
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger),
-		)
-
+		pid1, err := sys.Spawn(ctx, "Exchange1", actor1)
 		require.NoError(t, err)
 		require.NotNil(t, pid1)
 
@@ -2062,25 +2060,27 @@ func TestReceiveContext(t *testing.T) {
 	t.Run("With successful PipeTo", func(t *testing.T) {
 		askTimeout := time.Minute
 		ctx := context.TODO()
+		ports := dynaport.Get(1)
 
-		opts := []pidOption{
-			withInitMaxRetries(1),
-			withPassivationDisabled(),
-			withCustomLogger(log.DiscardLogger),
-		}
+		actorSystem, err := NewActorSystem("sys",
+			WithRemoting("127.0.0.1", int32(ports[0])),
+			WithLogger(log.DiscardLogger))
+
+		require.NoError(t, err)
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
 
-		ports := dynaport.Get(1)
 		// create actor1
 		actor1 := &exchanger{}
-		actorPath1 := address.New("Exchange1", "sys", "host", ports[0])
-		pid1, err := newPID(ctx, actorPath1, actor1, opts...)
+		pid1, err := actorSystem.Spawn(ctx, "Exchange1", actor1)
 		require.NoError(t, err)
 		require.NotNil(t, pid1)
 
 		// create actor2
 		actor2 := &exchanger{}
-		actorPath2 := address.New("Exchange2", "sys", "host", ports[0])
-		pid2, err := newPID(ctx, actorPath2, actor2, opts...)
+
+		pid2, err := actorSystem.Spawn(ctx, "Exchange2", actor2)
 		require.NoError(t, err)
 		require.NotNil(t, pid2)
 
@@ -2123,29 +2123,32 @@ func TestReceiveContext(t *testing.T) {
 		lib.Pause(time.Second)
 		assert.NoError(t, pid1.Shutdown(ctx))
 		assert.NoError(t, pid2.Shutdown(ctx))
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 	t.Run("With failed PipeTo", func(t *testing.T) {
 		ctx := context.TODO()
+		ports := dynaport.Get(1)
 
-		opts := []pidOption{
-			withInitMaxRetries(1),
-			withPassivationDisabled(),
-			withCustomLogger(log.DiscardLogger),
-		}
+		actorSystem, err := NewActorSystem("sys",
+			WithRemoting("127.0.0.1", int32(ports[0])),
+			WithLogger(log.DiscardLogger))
 
-		ports := dynaport.Get(1)
+		require.NoError(t, err)
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
 
 		// create actor1
 		actor1 := &exchanger{}
-		actorPath1 := address.New("Exchange1", "sys", "host", ports[0])
-		pid1, err := newPID(ctx, actorPath1, actor1, opts...)
+
+		pid1, err := actorSystem.Spawn(ctx, "Exchange1", actor1)
 		require.NoError(t, err)
 		require.NotNil(t, pid1)
 
 		// create actor2
 		actor2 := &exchanger{}
-		actorPath2 := address.New("Exchange2", "sys", "host", ports[0])
-		pid2, err := newPID(ctx, actorPath2, actor2, opts...)
+
+		pid2, err := actorSystem.Spawn(ctx, "Exchange2", actor2)
 		require.NoError(t, err)
 		require.NotNil(t, pid2)
 
@@ -2167,6 +2170,7 @@ func TestReceiveContext(t *testing.T) {
 		require.Error(t, messageContext.getError())
 		assert.NoError(t, pid1.Shutdown(ctx))
 		assert.NoError(t, pid2.Shutdown(ctx))
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 	t.Run("With successful SendAsync command", func(t *testing.T) {
 		ctx := context.Background()
@@ -2335,24 +2339,27 @@ func TestReceiveContext(t *testing.T) {
 	})
 	t.Run("With Stash when stash not set", func(t *testing.T) {
 		ctx := context.TODO()
-		// create an actor
-		opts := []pidOption{
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger),
-		}
-
 		ports := dynaport.Get(1)
+
+		actorSystem, err := NewActorSystem("sys",
+			WithRemoting("127.0.0.1", int32(ports[0])),
+			WithLogger(log.DiscardLogger))
+
+		require.NoError(t, err)
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
+
 		// create the actor path
-		actor := &stasQA{}
-		actorPath := address.New("stasQA", "sys", "host", ports[0])
-		pid, err := newPID(ctx, actorPath, actor, opts...)
+		actor := &stashQA{}
+		pid, err := actorSystem.Spawn(ctx, "stashQA", actor)
 		require.NoError(t, err)
 		require.NotNil(t, pid)
 
 		// wait for the actor to properly start
 		lib.Pause(5 * time.Millisecond)
 
-		// create a receive context
+		// create a receiveContext
 		receiveContext := &ReceiveContext{
 			ctx:     ctx,
 			message: new(testpb.TestSend),
@@ -2366,27 +2373,32 @@ func TestReceiveContext(t *testing.T) {
 		assert.EqualError(t, err, ErrStashBufferNotSet.Error())
 		err = pid.Shutdown(ctx)
 		assert.NoError(t, err)
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 	t.Run("With Unstash when stash not set", func(t *testing.T) {
 		ctx := context.TODO()
-		// create an actor
-		opts := []pidOption{
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger),
-		}
-
 		ports := dynaport.Get(1)
+
+		actorSystem, err := NewActorSystem("sys",
+			WithRemoting("127.0.0.1", int32(ports[0])),
+			WithLogger(log.DiscardLogger))
+
+		require.NoError(t, err)
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
+
 		// create the actor path
-		actor := &stasQA{}
-		actorPath := address.New("stasQA", "sys", "host", ports[0])
-		pid, err := newPID(ctx, actorPath, actor, opts...)
+		actor := &stashQA{}
+
+		pid, err := actorSystem.Spawn(ctx, "stashQA", actor)
 		require.NoError(t, err)
 		require.NotNil(t, pid)
 
 		// wait for the actor to properly start
 		lib.Pause(5 * time.Millisecond)
 
-		// create a receive context
+		// create a receiveContext
 		receiveContext := &ReceiveContext{
 			ctx:     ctx,
 			message: new(testpb.TestSend),
@@ -2400,20 +2412,25 @@ func TestReceiveContext(t *testing.T) {
 		assert.EqualError(t, err, ErrStashBufferNotSet.Error())
 		err = pid.Shutdown(ctx)
 		assert.NoError(t, err)
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 	t.Run("With UnstashAll when stash not set", func(t *testing.T) {
 		ctx := context.TODO()
-		// create an actor
-		opts := []pidOption{
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger),
-		}
-
 		ports := dynaport.Get(1)
+
+		actorSystem, err := NewActorSystem("sys",
+			WithRemoting("127.0.0.1", int32(ports[0])),
+			WithLogger(log.DiscardLogger))
+
+		require.NoError(t, err)
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
+
 		// create the actor path
-		actor := &stasQA{}
-		actorPath := address.New("stasQA", "sys", "host", ports[0])
-		pid, err := newPID(ctx, actorPath, actor, opts...)
+		actor := &stashQA{}
+
+		pid, err := actorSystem.Spawn(ctx, "stashQA", actor)
 		require.NoError(t, err)
 		require.NotNil(t, pid)
 
@@ -2434,6 +2451,7 @@ func TestReceiveContext(t *testing.T) {
 		assert.EqualError(t, err, ErrStashBufferNotSet.Error())
 		err = pid.Shutdown(ctx)
 		assert.NoError(t, err)
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 	t.Run("With successful RemoteForward", func(t *testing.T) {
 		ctx := context.TODO()
@@ -2546,6 +2564,9 @@ func TestReceiveContext(t *testing.T) {
 		// let us shutdown the rest
 		require.NoError(t, pidA.Shutdown(ctx))
 		require.NoError(t, pidB.Shutdown(ctx))
+
+		assert.NoError(t, actorSystem.Stop(ctx))
+		assert.NoError(t, actorSystem2.Stop(ctx))
 	})
 	t.Run("With successful RemoteForward case 2", func(t *testing.T) {
 		ctx := context.TODO()
@@ -2600,6 +2621,8 @@ func TestReceiveContext(t *testing.T) {
 		// let us shutdown the rest
 		require.NoError(t, pidA.Shutdown(ctx))
 		require.NoError(t, pidB.Shutdown(ctx))
+		assert.NoError(t, actorSystem.Stop(ctx))
+		assert.NoError(t, actorSystem2.Stop(ctx))
 	})
 	t.Run("With successful ForwardTo", func(t *testing.T) {
 		// create a context
@@ -2659,6 +2682,7 @@ func TestReceiveContext(t *testing.T) {
 		// let us shutdown the rest
 		require.NoError(t, actorSystem.Stop(ctx))
 		require.NoError(t, actorSystem2.Stop(ctx))
+		srv.Shutdown()
 	})
 	t.Run("With failed ForwardTo", func(t *testing.T) {
 		// create a context
@@ -2716,5 +2740,6 @@ func TestReceiveContext(t *testing.T) {
 		// let us shutdown the rest
 		require.NoError(t, actorSystem.Stop(ctx))
 		require.NoError(t, actorSystem2.Stop(ctx))
+		srv.Shutdown()
 	})
 }
diff --git a/actors/remoting_test.go b/actors/remoting_test.go
index 8b44663..8ff76a3 100644
--- a/actors/remoting_test.go
+++ b/actors/remoting_test.go
@@ -47,7 +47,7 @@ func TestRemoteTell(t *testing.T) {
 		// create the context
 		ctx := context.TODO()
 		// define the logger to use
-		logger := log.DiscardLogger
+		logger := log.DefaultLogger
 		// generate the remoting port
 		nodePorts := dynaport.Get(1)
 		remotingPort := nodePorts[0]
@@ -78,7 +78,7 @@ func TestRemoteTell(t *testing.T) {
 
 		remoting := NewRemoting()
 		// get the address of the actor
-		addr, err := remoting.RemoteLookup(ctx, host, remotingPort, actorName)
+		addr, err := remoting.RemoteLookup(ctx, sys.Host(), int(sys.Port()), actorName)
 		require.NoError(t, err)
 		// create a message to send to the test actor
 		message := new(testpb.TestSend)
@@ -105,7 +105,7 @@ func TestRemoteTell(t *testing.T) {
 		// generate the remoting port
 		nodePorts := dynaport.Get(1)
 		remotingPort := nodePorts[0]
-		host := "localhost"
+		host := "0.0.0.0"
 
 		// create the actor system
 		sys, err := NewActorSystem(
@@ -132,7 +132,7 @@ func TestRemoteTell(t *testing.T) {
 
 		remoting := NewRemoting()
 		// get the address of the actor
-		addr, err := remoting.RemoteLookup(ctx, host, remotingPort, actorName)
+		addr, err := remoting.RemoteLookup(ctx, sys.Host(), int(sys.Port()), actorName)
 		require.NoError(t, err)
 		from := address.NoSender()
 		err = remoting.RemoteTell(ctx, from, addr, nil)
@@ -237,7 +237,7 @@ func TestRemoteTell(t *testing.T) {
 		assert.NotNil(t, actorRef)
 
 		remoting := NewRemoting()
-		addr, err := remoting.RemoteLookup(ctx, host, remotingPort, actorName)
+		addr, err := remoting.RemoteLookup(ctx, sys.Host(), int(sys.Port()), actorName)
 		require.NoError(t, err)
 
 		// let us disable remoting
@@ -296,7 +296,7 @@ func TestRemoteTell(t *testing.T) {
 		remoting := NewRemoting()
 
 		// get the address of the actor
-		addr, err := remoting.RemoteLookup(ctx, host, remotingPort, actorName)
+		addr, err := remoting.RemoteLookup(ctx, sys.Host(), int(sys.Port()), actorName)
 		require.NoError(t, err)
 		// create a message to send to the test actor
 		messages := make([]proto.Message, 10)
@@ -411,7 +411,7 @@ func TestRemoteTell(t *testing.T) {
 		assert.NotNil(t, actorRef)
 
 		remoting := NewRemoting()
-		addr, err := remoting.RemoteLookup(ctx, host, remotingPort, actorName)
+		addr, err := remoting.RemoteLookup(ctx, sys.Host(), int(sys.Port()), actorName)
 		require.NoError(t, err)
 		from := address.NoSender()
 		// let us disable remoting
@@ -468,7 +468,7 @@ func TestRemoteTell(t *testing.T) {
 
 		remoting := NewRemoting()
 		// get the address of the actor
-		addr, err := remoting.RemoteLookup(ctx, host, remotingPort, actorName)
+		addr, err := remoting.RemoteLookup(ctx, sys.Host(), int(sys.Port()), actorName)
 		require.NoError(t, err)
 
 		// stop the actor when wait for cleanup to take place
@@ -526,7 +526,7 @@ func TestRemoteTell(t *testing.T) {
 
 		remoting := NewRemoting()
 		// get the address of the actor
-		addr, err := remoting.RemoteLookup(ctx, host, remotingPort, actorName)
+		addr, err := remoting.RemoteLookup(ctx, sys.Host(), int(sys.Port()), actorName)
 		require.NoError(t, err)
 
 		// stop the actor when wait for cleanup to take place
@@ -588,7 +588,7 @@ func TestRemoteAsk(t *testing.T) {
 			remoting := NewRemoting()
 			from := address.NoSender()
 			// get the address of the actor
-			addr, err := remoting.RemoteLookup(ctx, host, remotingPort, actorName)
+			addr, err := remoting.RemoteLookup(ctx, sys.Host(), int(sys.Port()), actorName)
 			require.NoError(t, err)
 
 			// create a message to send to the test actor
@@ -651,7 +651,7 @@ func TestRemoteAsk(t *testing.T) {
 
 			remoting := NewRemoting()
 			// get the address of the actor
-			addr, err := remoting.RemoteLookup(ctx, host, remotingPort, actorName)
+			addr, err := remoting.RemoteLookup(ctx, sys.Host(), int(sys.Port()), actorName)
 			require.NoError(t, err)
 
 			from := address.NoSender()
@@ -766,7 +766,7 @@ func TestRemoteAsk(t *testing.T) {
 
 			remoting := NewRemoting()
 			// get the address of the actor
-			addr, err := remoting.RemoteLookup(ctx, host, remotingPort, actorName)
+			addr, err := remoting.RemoteLookup(ctx, sys.Host(), int(sys.Port()), actorName)
 			require.NoError(t, err)
 
 			// let us disable remoting
@@ -826,7 +826,7 @@ func TestRemoteAsk(t *testing.T) {
 
 			remoting := NewRemoting()
 			// get the address of the actor
-			addr, err := remoting.RemoteLookup(ctx, host, remotingPort, actorName)
+			addr, err := remoting.RemoteLookup(ctx, sys.Host(), int(sys.Port()), actorName)
 			require.NoError(t, err)
 
 			from := address.NoSender()
@@ -953,7 +953,7 @@ func TestRemoteAsk(t *testing.T) {
 
 			remoting := NewRemoting()
 
-			addr, err := remoting.RemoteLookup(ctx, host, remotingPort, actorName)
+			addr, err := remoting.RemoteLookup(ctx, sys.Host(), int(sys.Port()), actorName)
 			require.NoError(t, err)
 
 			// let us disable remoting
@@ -1018,7 +1018,7 @@ func TestRemoteAsk(t *testing.T) {
 			remoting := NewRemoting()
 			from := address.NoSender()
 			// get the address of the actor
-			addr, err := remoting.RemoteLookup(ctx, host, remotingPort, actorName)
+			addr, err := remoting.RemoteLookup(ctx, sys.Host(), int(sys.Port()), actorName)
 			require.NoError(t, err)
 
 			// stop the actor when wait for cleanup to take place
@@ -1079,7 +1079,7 @@ func TestRemoteAsk(t *testing.T) {
 
 			remoting := NewRemoting()
 			// get the address of the actor
-			addr, err := remoting.RemoteLookup(ctx, host, remotingPort, actorName)
+			addr, err := remoting.RemoteLookup(ctx, sys.Host(), int(sys.Port()), actorName)
 			require.NoError(t, err)
 
 			// stop the actor when wait for cleanup to take place
@@ -1140,7 +1140,7 @@ func TestAPIRemoteLookup(t *testing.T) {
 			// create a test actor
 			actorName := "test"
 			// get the address of the actor
-			addr, err := remoting.RemoteLookup(ctx, host, remotingPort, actorName)
+			addr, err := remoting.RemoteLookup(ctx, sys.Host(), int(sys.Port()), actorName)
 			require.Error(t, err)
 			require.EqualError(t, err, "failed_precondition: remoting is not enabled")
 			require.Nil(t, addr)
@@ -1189,7 +1189,7 @@ func TestAPIRemoteReSpawn(t *testing.T) {
 			// create a test actor
 			actorName := "test"
 			// get the address of the actor
-			err = remoting.RemoteReSpawn(ctx, host, remotingPort, actorName)
+			err = remoting.RemoteReSpawn(ctx, sys.Host(), int(sys.Port()), actorName)
 			require.Error(t, err)
 			require.EqualError(t, err, "failed_precondition: remoting is not enabled")
 
@@ -1240,7 +1240,7 @@ func TestAPIRemoteReSpawn(t *testing.T) {
 			assert.Zero(t, pid.restartCount.Load())
 			remoting := NewRemoting()
 			// get the address of the actor
-			err = remoting.RemoteReSpawn(ctx, host, remotingPort, actorName)
+			err = remoting.RemoteReSpawn(ctx, sys.Host(), int(sys.Port()), actorName)
 			require.NoError(t, err)
 
 			assert.EqualValues(t, 1, pid.restartCount.Load())
@@ -1291,7 +1291,7 @@ func TestAPIRemoteStop(t *testing.T) {
 			// create a test actor
 			actorName := "test"
 			// get the address of the actor
-			err = remoting.RemoteStop(ctx, host, remotingPort, actorName)
+			err = remoting.RemoteStop(ctx, sys.Host(), int(sys.Port()), actorName)
 			require.Error(t, err)
 			require.EqualError(t, err, "failed_precondition: remoting is not enabled")
 
@@ -1344,9 +1344,11 @@ func TestAPIRemoteStop(t *testing.T) {
 			remoting := NewRemoting()
 
 			// get the address of the actor
-			err = remoting.RemoteStop(ctx, host, remotingPort, actorName)
+			err = remoting.RemoteStop(ctx, sys.Host(), int(sys.Port()), actorName)
 			require.NoError(t, err)
 
+			lib.Pause(time.Second)
+
 			assert.Empty(t, sys.Actors())
 
 			// stop the actor after some time
@@ -1391,7 +1393,7 @@ func TestAPIRemoteSpawn(t *testing.T) {
 
 			remoting := NewRemoting()
 			// fetching the address of the that actor should return nil address
-			addr, err := remoting.RemoteLookup(ctx, host, remotingPort, actorName)
+			addr, err := remoting.RemoteLookup(ctx, sys.Host(), int(sys.Port()), actorName)
 			require.NoError(t, err)
 			require.Nil(t, addr)
 
@@ -1463,12 +1465,12 @@ func TestAPIRemoteSpawn(t *testing.T) {
 
 			remoting := NewRemoting()
 			// fetching the address of the that actor should return nil address
-			addr, err := remoting.RemoteLookup(ctx, host, remotingPort, actorName)
+			addr, err := remoting.RemoteLookup(ctx, sys.Host(), int(sys.Port()), actorName)
 			require.NoError(t, err)
 			require.Nil(t, addr)
 
 			// spawn the remote actor
-			err = remoting.RemoteSpawn(ctx, host, remotingPort, actorName, "actors.exchanger")
+			err = remoting.RemoteSpawn(ctx, sys.Host(), int(sys.Port()), actorName, "actors.exchanger")
 			require.Error(t, err)
 			assert.EqualError(t, err, ErrTypeNotRegistered.Error())
 
diff --git a/actors/scheduler_test.go b/actors/scheduler_test.go
index 76110f8..eaddd7a 100644
--- a/actors/scheduler_test.go
+++ b/actors/scheduler_test.go
@@ -133,22 +133,31 @@ func TestScheduler(t *testing.T) {
 		assert.NoError(t, err)
 	})
 	t.Run("With ScheduleOnce with scheduler not started", func(t *testing.T) {
+		// create the context
 		ctx := context.TODO()
-		scheduler := newScheduler(log.DiscardLogger, time.Second)
-		ports := dynaport.Get(1)
+		// define the logger to use
+		logger := log.DiscardLogger
+		// create the actor system
+		newActorSystem, err := NewActorSystem(
+			"test",
+			WithLogger(logger),
+			WithJanitorInterval(time.Minute),
+			WithPassivationDisabled(),
+		)
+		// assert there are no error
+		require.NoError(t, err)
 
-		// create the actor path
-		actorPath := address.New("Test", "sys", "host", ports[0])
+		// start the actor system
+		err = newActorSystem.Start(ctx)
+		assert.NoError(t, err)
 
-		// create the actor ref
-		pid, err := newPID(
-			ctx,
-			actorPath,
-			newActor(),
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger),
-		)
+		lib.Pause(time.Second)
 
+		scheduler := newActorSystem.(*actorSystem).scheduler
+		scheduler.Stop(ctx)
+
+		// create the actor ref
+		pid, err := newActorSystem.Spawn(ctx, "test", newActor())
 		require.NoError(t, err)
 		assert.NotNil(t, pid)
 
@@ -195,7 +204,7 @@ func TestScheduler(t *testing.T) {
 
 		remoting := NewRemoting()
 		// get the address of the actor
-		addr, err := remoting.RemoteLookup(ctx, host, remotingPort, actorName)
+		addr, err := remoting.RemoteLookup(ctx, newActorSystem.Host(), int(newActorSystem.Port()), actorName)
 		require.NoError(t, err)
 
 		// send a message to the actor after 100 ms
@@ -255,7 +264,7 @@ func TestScheduler(t *testing.T) {
 
 		remoting := NewRemoting()
 		// get the address of the actor
-		addr, err := remoting.RemoteLookup(ctx, host, remotingPort, actorName)
+		addr, err := remoting.RemoteLookup(ctx, newActorSystem.Host(), int(newActorSystem.Port()), actorName)
 		require.NoError(t, err)
 
 		// send a message to the actor after 100 ms
@@ -432,7 +441,7 @@ func TestScheduler(t *testing.T) {
 
 		remoting := NewRemoting()
 		// get the address of the actor
-		addr, err := remoting.RemoteLookup(ctx, host, remotingPort, actorName)
+		addr, err := remoting.RemoteLookup(ctx, newActorSystem.Host(), int(newActorSystem.Port()), actorName)
 		require.NoError(t, err)
 
 		// send a message to the actor after 100 ms
@@ -485,7 +494,7 @@ func TestScheduler(t *testing.T) {
 
 		remoting := NewRemoting()
 		// get the address of the actor
-		addr, err := remoting.RemoteLookup(ctx, host, remotingPort, actorName)
+		addr, err := remoting.RemoteLookup(ctx, newActorSystem.Host(), int(newActorSystem.Port()), actorName)
 		require.NoError(t, err)
 
 		// send a message to the actor after 100 ms
@@ -537,7 +546,7 @@ func TestScheduler(t *testing.T) {
 
 		remoting := NewRemoting()
 		// get the address of the actor
-		addr, err := remoting.RemoteLookup(ctx, host, remotingPort, actorName)
+		addr, err := remoting.RemoteLookup(ctx, newActorSystem.Host(), int(newActorSystem.Port()), actorName)
 		require.NoError(t, err)
 
 		// send a message to the actor after 100 ms
@@ -729,7 +738,7 @@ func TestScheduler(t *testing.T) {
 
 		remoting := NewRemoting()
 		// get the address of the actor
-		addr, err := remoting.RemoteLookup(ctx, host, remotingPort, actorName)
+		addr, err := remoting.RemoteLookup(ctx, newActorSystem.Host(), int(newActorSystem.Port()), actorName)
 		require.NoError(t, err)
 
 		// send a message to the actor after 100 ms
@@ -793,7 +802,7 @@ func TestScheduler(t *testing.T) {
 
 		remoting := NewRemoting()
 		// get the address of the actor
-		addr, err := remoting.RemoteLookup(ctx, host, remotingPort, actorName)
+		addr, err := remoting.RemoteLookup(ctx, newActorSystem.Host(), int(newActorSystem.Port()), actorName)
 		require.NoError(t, err)
 
 		// send a message to the actor after 100 ms
@@ -842,7 +851,7 @@ func TestScheduler(t *testing.T) {
 
 		remoting := NewRemoting()
 		// get the address of the actor
-		addr, err := remoting.RemoteLookup(ctx, host, remotingPort, actorName)
+		addr, err := remoting.RemoteLookup(ctx, newActorSystem.Host(), int(newActorSystem.Port()), actorName)
 		require.NoError(t, err)
 
 		require.NoError(t, newActorSystem.Kill(ctx, actorName))
diff --git a/actors/stash_test.go b/actors/stash_test.go
index d7b908f..94b075c 100644
--- a/actors/stash_test.go
+++ b/actors/stash_test.go
@@ -33,7 +33,6 @@ import (
 	"github.com/stretchr/testify/require"
 	"github.com/travisjeffery/go-dynaport"
 
-	"github.com/tochemey/goakt/v2/address"
 	"github.com/tochemey/goakt/v2/internal/lib"
 	"github.com/tochemey/goakt/v2/log"
 	"github.com/tochemey/goakt/v2/test/data/testpb"
@@ -42,19 +41,23 @@ import (
 func TestStash(t *testing.T) {
 	t.Run("With happy path", func(t *testing.T) {
 		ctx := context.TODO()
-		// create a Ping actor
-		opts := []pidOption{
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger),
-			withStash(),
-		}
-
 		ports := dynaport.Get(1)
+		host := "127.0.0.1"
+
+		actorSystem, err := NewActorSystem("testSys",
+			WithRemoting(host, int32(ports[0])),
+			WithStash(),
+			WithLogger(log.DiscardLogger))
+		require.NoError(t, err)
+		require.NotNil(t, actorSystem)
+
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
 
 		// create the actor path
-		actor := &stasQA{}
-		actorPath := address.New("stasQA", "sys", "host", ports[0])
-		pid, err := newPID(ctx, actorPath, actor, opts...)
+		actor := &stashQA{}
+		pid, err := actorSystem.Spawn(ctx, "Stash", actor)
 		require.NoError(t, err)
 		require.NotNil(t, pid)
 
@@ -96,7 +99,7 @@ func TestStash(t *testing.T) {
 
 		// add some pause here due to async calls
 		lib.Pause(time.Second)
-		assert.NoError(t, Tell(ctx, pid, new(testpb.TestUnstashAll)))
+		require.NoError(t, Tell(ctx, pid, new(testpb.TestUnstashAll)))
 
 		// add some pause here due to async calls
 		lib.Pause(time.Second)
@@ -108,21 +111,27 @@ func TestStash(t *testing.T) {
 		require.NoError(t, err)
 
 		lib.Pause(time.Second)
-		assert.False(t, pid.IsRunning())
+		require.False(t, pid.IsRunning())
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 	t.Run("With stash failure", func(t *testing.T) {
 		ctx := context.TODO()
-		// create an actor
-		opts := []pidOption{
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger),
-		}
-
 		ports := dynaport.Get(1)
+		host := "127.0.0.1"
+
+		actorSystem, err := NewActorSystem("testSys",
+			WithRemoting(host, int32(ports[0])),
+			WithLogger(log.DiscardLogger))
+		require.NoError(t, err)
+		require.NotNil(t, actorSystem)
+
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
+
 		// create the actor path
-		actor := &stasQA{}
-		actorPath := address.New("stasQA", "sys", "host", ports[0])
-		pid, err := newPID(ctx, actorPath, actor, opts...)
+		actor := &stashQA{}
+		pid, err := actorSystem.Spawn(ctx, "Stash", actor)
 		require.NoError(t, err)
 		require.NotNil(t, pid)
 
@@ -135,19 +144,27 @@ func TestStash(t *testing.T) {
 
 		err = pid.Shutdown(ctx)
 		assert.NoError(t, err)
+		lib.Pause(time.Second)
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 	t.Run("With unstash when stash not set", func(t *testing.T) {
 		ctx := context.TODO()
-		// create a Ping actor
-		opts := []pidOption{
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger),
-		}
 		ports := dynaport.Get(1)
+		host := "127.0.0.1"
+
+		actorSystem, err := NewActorSystem("testSys",
+			WithRemoting(host, int32(ports[0])),
+			WithLogger(log.DiscardLogger))
+		require.NoError(t, err)
+		require.NotNil(t, actorSystem)
+
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
+
 		// create the actor path
-		actor := &stasQA{}
-		actorPath := address.New("stasQA", "sys", "host", ports[0])
-		pid, err := newPID(ctx, actorPath, actor, opts...)
+		actor := &stashQA{}
+		pid, err := actorSystem.Spawn(ctx, "Stash", actor)
 		require.NoError(t, err)
 		require.NotNil(t, pid)
 
@@ -164,22 +181,28 @@ func TestStash(t *testing.T) {
 
 		err = pid.Shutdown(ctx)
 		assert.NoError(t, err)
+		lib.Pause(time.Second)
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 	t.Run("With unstash when there is no stashed message", func(t *testing.T) {
 		ctx := context.TODO()
-		// create a Ping actor
-		opts := []pidOption{
-			withInitMaxRetries(1),
-			withCustomLogger(log.DiscardLogger),
-			withStash(),
-		}
-
 		ports := dynaport.Get(1)
+		host := "127.0.0.1"
+
+		actorSystem, err := NewActorSystem("testSys",
+			WithRemoting(host, int32(ports[0])),
+			WithStash(),
+			WithLogger(log.DiscardLogger))
+		require.NoError(t, err)
+		require.NotNil(t, actorSystem)
+
+		require.NoError(t, actorSystem.Start(ctx))
+
+		lib.Pause(time.Second)
 
 		// create the actor path
-		actor := &stasQA{}
-		actorPath := address.New("stasQA", "sys", "host", ports[0])
-		pid, err := newPID(ctx, actorPath, actor, opts...)
+		actor := &stashQA{}
+		pid, err := actorSystem.Spawn(ctx, "Stash", actor)
 		require.NoError(t, err)
 		require.NotNil(t, pid)
 
@@ -234,5 +257,7 @@ func TestStash(t *testing.T) {
 
 		err = pid.Shutdown(ctx)
 		assert.NoError(t, err)
+		lib.Pause(time.Second)
+		assert.NoError(t, actorSystem.Stop(ctx))
 	})
 }
diff --git a/internal/slice/lock_free_test.go b/internal/slice/thread_safe_test.go
similarity index 98%
rename from internal/slice/lock_free_test.go
rename to internal/slice/thread_safe_test.go
index de2ca45..a458344 100644
--- a/internal/slice/lock_free_test.go
+++ b/internal/slice/thread_safe_test.go
@@ -32,7 +32,7 @@ import (
 
 func TestSlice(t *testing.T) {
 	// create a concurrent slice of integer
-	sl := NewLockFree[int]()
+	sl := NewThreadSafe[int]()
 
 	// add some items
 	sl.Append(2)