Repository: Tochemey/goakt
Pull request #45 (2023-05-23 22:48:12)

feat: refactor and deps upgrade


Patch:
diff --git a/actors/actor_system.go b/actors/actor_system.go
index 636bce6..e1bf3bb 100644
--- a/actors/actor_system.go
+++ b/actors/actor_system.go
@@ -37,14 +37,8 @@ var once resync.Once
 type ActorSystem interface {
 	// Name returns the actor system name
 	Name() string
-	// NodeAddr returns the node where the actor system is running
-	NodeAddr() string
 	// Actors returns the list of Actors that are alive in the actor system
 	Actors() []PID
-	// Host returns the actor system host address
-	Host() string
-	// Port returns the actor system host port
-	Port() int
 	// Start starts the actor system
 	Start(ctx context.Context) error
 	// Stop stops the actor system
@@ -78,16 +72,10 @@ type actorSystem struct {
 
 	// Specifies the actor system name
 	name string
-	// Specifies the node where the actor system is located
-	nodeAddr string
 	// map of actors in the system
 	actors cmp.ConcurrentMap[string, PID]
 	//  specifies the logger to use
 	logger log.Logger
-	// specifies the host address
-	host string
-	// specifies the port
-	port int
 	// actor system configuration
 	config *Config
 	// states whether the actor system has started or not
@@ -120,21 +108,14 @@ func NewActorSystem(config *Config) (ActorSystem, error) {
 	once.Do(func() {
 		system = &actorSystem{
 			name:        config.Name(),
-			nodeAddr:    config.NodeHostAndPort(),
 			actors:      cmp.New[PID](),
 			logger:      config.Logger(),
-			host:        "",
-			port:        0,
 			config:      config,
 			hasStarted:  atomic.NewBool(false),
 			telemetry:   config.telemetry,
 			typesLoader: NewTypesLoader(nil),
 			clusterChan: make(chan *goaktpb.WireActor, 10),
 		}
-		// set host and port
-		host, port := config.HostAndPort()
-		system.host = host
-		system.port = port
 		// set the reflection
 		system.reflection = NewReflection(system.typesLoader)
 	})
@@ -161,8 +142,13 @@ func (a *actorSystem) StartActor(ctx context.Context, name string, actor Actor)
 	if !a.hasStarted.Load() {
 		return nil
 	}
-	// get the path of the given actor
-	actorPath := NewPath(name, NewLocalAddress(protocol, a.name, a.host, a.port))
+	// set the default actor path assuming we are running locally
+	actorPath := NewPath(name, NewAddress(protocol, a.name, "", -1))
+	// set the actor path with the remoting is enabled
+	if a.config.remotingEnabled {
+		// get the path of the given actor
+		actorPath = NewPath(name, NewAddress(protocol, a.name, a.config.remotingHost, int(a.config.remotingPort)))
+	}
 	// check whether the given actor already exist in the system or not
 	pid, exist := a.actors.Get(actorPath.String())
 	// actor already exist no need recreate it.
@@ -226,8 +212,13 @@ func (a *actorSystem) StopActor(ctx context.Context, name string) error {
 	if !a.hasStarted.Load() {
 		return errors.New("actor system has not started yet")
 	}
-	// get the path of the given actor
-	actorPath := NewPath(name, NewLocalAddress(protocol, a.name, a.host, a.port))
+	// set the default actor path assuming we are running locally
+	actorPath := NewPath(name, NewAddress(protocol, a.name, "", -1))
+	// set the actor path with the remoting is enabled
+	if a.config.remotingEnabled {
+		// get the path of the given actor
+		actorPath = NewPath(name, NewAddress(protocol, a.name, a.config.remotingHost, int(a.config.remotingPort)))
+	}
 	// check whether the given actor already exist in the system or not
 	pid, exist := a.actors.Get(actorPath.String())
 	// actor is found.
@@ -247,8 +238,13 @@ func (a *actorSystem) RestartActor(ctx context.Context, name string) (PID, error
 	if !a.hasStarted.Load() {
 		return nil, errors.New("actor system has not started yet")
 	}
-	// get the path of the given actor
-	actorPath := NewPath(name, NewLocalAddress(protocol, a.name, a.host, a.port))
+	// set the default actor path assuming we are running locally
+	actorPath := NewPath(name, NewAddress(protocol, a.name, "", -1))
+	// set the actor path with the remoting is enabled
+	if a.config.remotingEnabled {
+		// get the path of the given actor
+		actorPath = NewPath(name, NewAddress(protocol, a.name, a.config.remotingHost, int(a.config.remotingPort)))
+	}
 	// check whether the given actor already exist in the system or not
 	pid, exist := a.actors.Get(actorPath.String())
 	// actor is found.
@@ -268,21 +264,6 @@ func (a *actorSystem) Name() string {
 	return a.name
 }
 
-// NodeAddr returns the node where the actor system is running
-func (a *actorSystem) NodeAddr() string {
-	return a.nodeAddr
-}
-
-// Host returns the actor system node host address
-func (a *actorSystem) Host() string {
-	return a.host
-}
-
-// Port returns the actor system node port
-func (a *actorSystem) Port() int {
-	return a.port
-}
-
 // Actors returns the list of Actors that are alive in the actor system
 func (a *actorSystem) Actors() []PID {
 	// get the actors from the actor map
@@ -376,7 +357,7 @@ func (a *actorSystem) Stop(ctx context.Context) error {
 	// add a span context
 	ctx, span := telemetry.SpanContext(ctx, "Stop")
 	defer span.End()
-	a.logger.Infof("%s ActorSystem is shutting down on Cluster=%s..:)", a.name, a.nodeAddr)
+	a.logger.Infof("ActorSystem is shutting down on Cluster=%s..:)", a.name)
 
 	// stop the remoting server
 	if a.config.remotingEnabled {
@@ -432,9 +413,17 @@ func (a *actorSystem) RemoteLookup(ctx context.Context, request *connect.Request
 	// first let us make a copy of the incoming request
 	reqCopy := request.Msg
 
+	// set the actor path with the remoting is enabled
+	if !a.config.remotingEnabled {
+		return nil, connect.NewError(connect.CodeFailedPrecondition, ErrRemotingNotEnabled)
+	}
+
+	// get the remoting server address
+	nodeAddr := fmt.Sprintf("%s:%d", a.config.remotingHost, a.config.remotingPort)
+
 	// let us validate the host and port
 	hostAndPort := fmt.Sprintf("%s:%d", reqCopy.GetHost(), reqCopy.GetPort())
-	if hostAndPort != a.nodeAddr {
+	if hostAndPort != nodeAddr {
 		// log the error
 		logger.Error(ErrRemoteSendInvalidNode.Message())
 		// here message is sent to the wrong actor system node
@@ -443,7 +432,7 @@ func (a *actorSystem) RemoteLookup(ctx context.Context, request *connect.Request
 
 	// construct the actor address
 	name := reqCopy.GetName()
-	actorPath := NewPath(name, NewLocalAddress(protocol, a.Name(), reqCopy.GetHost(), int(reqCopy.GetPort())))
+	actorPath := NewPath(name, NewAddress(protocol, a.Name(), reqCopy.GetHost(), int(reqCopy.GetPort())))
 	// start or get the PID of the actor
 	// check whether the given actor already exist in the system or not
 	pid, exist := a.actors.Get(actorPath.String())
@@ -473,9 +462,17 @@ func (a *actorSystem) RemoteAsk(ctx context.Context, request *connect.Request[go
 	// first let us make a copy of the incoming request
 	reqCopy := request.Msg
 
+	// set the actor path with the remoting is enabled
+	if !a.config.remotingEnabled {
+		return nil, connect.NewError(connect.CodeFailedPrecondition, ErrRemotingNotEnabled)
+	}
+
+	// get the remoting server address
+	nodeAddr := fmt.Sprintf("%s:%d", a.config.remotingHost, a.config.remotingPort)
+
 	// let us validate the host and port
 	hostAndPort := fmt.Sprintf("%s:%d", reqCopy.GetRemoteMessage().GetReceiver().GetHost(), reqCopy.GetRemoteMessage().GetReceiver().GetPort())
-	if hostAndPort != a.nodeAddr {
+	if hostAndPort != nodeAddr {
 		// log the error
 		logger.Error(ErrRemoteSendInvalidNode.Message())
 		// here message is sent to the wrong actor system node
@@ -484,7 +481,8 @@ func (a *actorSystem) RemoteAsk(ctx context.Context, request *connect.Request[go
 
 	// construct the actor address
 	name := reqCopy.GetRemoteMessage().GetReceiver().GetName()
-	actorPath := NewPath(name, NewLocalAddress(protocol, a.name, a.host, a.port))
+	actorPath := NewPath(name, NewAddress(protocol, a.name, a.config.remotingHost, int(a.config.remotingPort)))
+
 	// start or get the PID of the actor
 	// check whether the given actor already exist in the system or not
 	pid, exist := a.actors.Get(actorPath.String())
@@ -527,9 +525,18 @@ func (a *actorSystem) RemoteTell(ctx context.Context, request *connect.Request[g
 	reqCopy := request.Msg
 
 	receiver := reqCopy.GetRemoteMessage().GetReceiver()
+
+	// set the actor path with the remoting is enabled
+	if !a.config.remotingEnabled {
+		return nil, connect.NewError(connect.CodeFailedPrecondition, ErrRemotingNotEnabled)
+	}
+
+	// get the remoting server address
+	nodeAddr := fmt.Sprintf("%s:%d", a.config.remotingHost, a.config.remotingPort)
+
 	// let us validate the host and port
 	hostAndPort := fmt.Sprintf("%s:%d", receiver.GetHost(), receiver.GetPort())
-	if hostAndPort != a.nodeAddr {
+	if hostAndPort != nodeAddr {
 		// log the error
 		logger.Error(ErrRemoteSendInvalidNode.Message())
 		// here message is sent to the wrong actor system node
@@ -539,7 +546,7 @@ func (a *actorSystem) RemoteTell(ctx context.Context, request *connect.Request[g
 	// construct the actor address
 	actorPath := NewPath(
 		receiver.GetName(),
-		NewLocalAddress(
+		NewAddress(
 			protocol,
 			a.Name(),
 			receiver.GetHost(),
@@ -632,6 +639,8 @@ func (a *actorSystem) enableClustering(ctx context.Context) {
 	<-bootstrapChan
 	timer.Stop()
 
+	// set the remoting host
+	a.config.remotingHost = cluster.NodeHost()
 	// let us enable remoting as well if not yet enabled
 	if !a.config.remotingEnabled {
 		a.enableRemoting(ctx)
@@ -659,7 +668,8 @@ func (a *actorSystem) enableRemoting(context.Context) {
 	)
 	mux.Handle(path, handler)
 	// create the address
-	serverAddr := fmt.Sprintf(":%d", a.Port())
+	serverAddr := fmt.Sprintf(":%d", a.config.remotingPort)
+
 	// create a http service instance
 	// TODO revisit the timeouts
 	// reference: https://adam-p.ca/blog/2022/01/golang-http-server-timeouts/
@@ -690,7 +700,10 @@ func (a *actorSystem) enableRemoting(context.Context) {
 
 	// listen and service requests
 	if err := a.remotingServer.ListenAndServe(); err != nil {
-		a.logger.Panic(errors.Wrap(err, "failed to start remoting service"))
+		// check the error type
+		if !errors.Is(err, http.ErrServerClosed) {
+			a.logger.Panic(errors.Wrap(err, "failed to start remoting service"))
+		}
 	}
 }
 
@@ -701,11 +714,9 @@ func (a *actorSystem) reset() {
 	a.hasStarted = atomic.NewBool(false)
 	a.telemetry = nil
 	a.actors = cmp.New[PID]()
-	a.nodeAddr = ""
 	a.name = ""
-	a.host = ""
-	a.port = -1
 	a.logger = nil
+	a.remotingServer = nil
 	once.Reset()
 }
 
diff --git a/actors/address.go b/actors/address.go
new file mode 100644
index 0000000..a8c73a1
--- /dev/null
+++ b/actors/address.go
@@ -0,0 +1,138 @@
+package actors
+
+import (
+	"bytes"
+	"strconv"
+
+	"github.com/pkg/errors"
+)
+
+const (
+	protocol = "goakt"
+)
+
+var (
+	ErrLocalAddress  = errors.New("address is a local address")
+	ErrRemoteAddress = errors.New("address is a remote address")
+)
+
+// Address represents the physical location under which an Actor can be
+// reached. Examples are local addresses, identified by the ActorSystem’s name,
+// and remote addresses, identified by protocol, host and port.
+type Address struct {
+	// host is the host address
+	host string
+	// port is the port number
+	port int
+	// system is the actor system name
+	system string
+	// protocol is the protocol
+	protocol string
+}
+
+// NewAddress creates an instance of Address
+func NewAddress(protocol string, system string, host string, port int) *Address {
+	return &Address{
+		host:     host,
+		port:     port,
+		system:   system,
+		protocol: protocol,
+	}
+}
+
+// WithHost sets the hosts of a given Address and returns a new instance of the address
+func (a *Address) WithHost(host string) (*Address, error) {
+	// only allow this operation if the given address is a remote one
+	if a.IsLocal() {
+		return nil, ErrLocalAddress
+	}
+	return NewAddress(a.Protocol(), a.System(), host, a.Port()), nil
+}
+
+// WithPort sets the port of a given Address and returns a new instance of the address
+func (a *Address) WithPort(port int) (*Address, error) {
+	// only allow this operation if the given address is a remote one
+	if a.IsLocal() {
+		return nil, ErrLocalAddress
+	}
+	return NewAddress(a.Protocol(), a.System(), a.System(), port), nil
+}
+
+// WithSystem sets the actor system of a given Address and returns a new instance of the address
+func (a *Address) WithSystem(system string) *Address {
+	return NewAddress(a.Protocol(), system, a.Host(), a.Port())
+}
+
+// Host returns the host
+func (a *Address) Host() string {
+	return a.host
+}
+
+// Port returns the port number
+func (a *Address) Port() int {
+	return a.port
+}
+
+// System returns the actor system name
+func (a *Address) System() string {
+	return a.system
+}
+
+// Protocol returns the protocol
+func (a *Address) Protocol() string {
+	return a.protocol
+}
+
+// HostPort returns the host and port in the following string format
+// @host:port
+func (a *Address) HostPort() string {
+	// create a bytes buffer instance
+	buf := bytes.NewBuffer(nil)
+	// write the host and port value when it is remote
+	if a.IsRemote() {
+		buf.WriteString(a.host)
+		buf.WriteByte(':')
+		buf.WriteString(strconv.Itoa(a.port))
+	}
+
+	// return the constructed string
+	return buf.String()
+}
+
+// String returns the canonical String representation of this Address formatted as:
+// `protocol://system@host:port`
+func (a *Address) String() string {
+	// if the protocol is not messages
+	// then panic
+	if a.protocol != protocol {
+		panic("invalid protocol")
+	}
+	// create a bytes buffer instance
+	buf := bytes.NewBuffer(nil)
+	// write the protocol field to bytes buffer
+	buf.WriteString(a.protocol)
+	buf.WriteString("://")
+	buf.WriteString(a.system)
+	buf.WriteByte('@')
+
+	// write the host and port to the bytes buffer when it is remote
+	if a.IsRemote() {
+		buf.WriteString(a.host)
+		buf.WriteByte(':')
+		buf.WriteString(strconv.Itoa(a.port))
+	}
+
+	// returns the constructed string value
+	return buf.String()
+}
+
+// IsLocal helps set the actor address locally
+func (a *Address) IsLocal() bool {
+	return len(a.host) == 0
+}
+
+// IsRemote states whether the actor address is in the remote environment
+// This happens when remoting is enabled
+func (a *Address) IsRemote() bool {
+	return len(a.host) > 0 && a.port > 0
+}
diff --git a/actors/config.go b/actors/config.go
index 6ee81e2..c61489b 100644
--- a/actors/config.go
+++ b/actors/config.go
@@ -21,9 +21,6 @@ var (
 type Config struct {
 	// Specifies the actor system name
 	name string
-	// Specifies the Node Host and IP address
-	// example: 127.0.0.1:8888
-	nodeHostAndPort string
 	// Specifies the logger to use in the system
 	logger log.Logger
 	// Specifies at what point in time to passivate the actor.
@@ -43,6 +40,10 @@ type Config struct {
 	// Specifies whether remoting is enabled.
 	// This allows to handle remote messaging
 	remotingEnabled bool
+	// Specifies the remoting port
+	remotingPort int32
+	// Specifies the remoting host
+	remotingHost string
 	// convenient field to check cluster setup
 	clusterEnabled bool
 	// cluster discovery method
@@ -50,7 +51,7 @@ type Config struct {
 }
 
 // NewConfig creates an instance of Config
-func NewConfig(name, nodeHostAndPort string, options ...Option) (*Config, error) {
+func NewConfig(name string, options ...Option) (*Config, error) {
 	// check whether the name is set or not
 	if name == "" {
 		return nil, ErrNameRequired
@@ -59,14 +60,9 @@ func NewConfig(name, nodeHostAndPort string, options ...Option) (*Config, error)
 		return nil, ErrInvalidActorSystemName
 	}
 
-	// check whether the node host and port is set and valid
-	if err := validateHostAndPort(nodeHostAndPort); err != nil {
-		return nil, err
-	}
 	// create an instance of config
 	config := &Config{
 		name:                name,
-		nodeHostAndPort:     nodeHostAndPort,
 		logger:              log.DefaultLogger,
 		expireActorAfter:    2 * time.Second,
 		replyTimeout:        100 * time.Millisecond,
@@ -88,11 +84,6 @@ func (c Config) Name() string {
 	return c.name
 }
 
-// NodeHostAndPort returns the node host and port
-func (c Config) NodeHostAndPort() string {
-	return c.nodeHostAndPort
-}
-
 // Logger returns the log
 func (c Config) Logger() log.Logger {
 	return c.logger
@@ -113,14 +104,6 @@ func (c Config) ActorInitMaxRetries() int {
 	return c.actorInitMaxRetries
 }
 
-// HostAndPort returns the host and the port
-func (c Config) HostAndPort() (host string, port int) {
-	// no need to check for the error because of the previous validation
-	host, portStr, _ := net.SplitHostPort(c.nodeHostAndPort)
-	port, _ = strconv.Atoi(portStr)
-	return
-}
-
 // SupervisorStrategy specifies the supervisor strategy
 func (c Config) SupervisorStrategy() StrategyDirective {
 	return c.supervisorStrategy
@@ -221,16 +204,21 @@ func WithTelemetry(telemetry *telemetry.Telemetry) Option {
 }
 
 // WithRemoting enables remoting on the actor system
-func WithRemoting() Option {
+func WithRemoting(host string, port int32) Option {
 	return OptionFunc(func(config *Config) {
 		config.remotingEnabled = true
+		config.remotingPort = port
+		config.remotingHost = host
 	})
 }
 
-// WithClustering enables clustering on the actor system
-func WithClustering(disco discovery.Discovery) Option {
+// WithClustering enables clustering on the actor system. This enables remoting on the actor system as well
+// and set the remotingHost to the cluster node host when the cluster is fully enabled.
+func WithClustering(disco discovery.Discovery, remotingPort int32) Option {
 	return OptionFunc(func(config *Config) {
 		config.clusterEnabled = true
+		config.remotingEnabled = true
+		config.remotingPort = remotingPort
 		config.disco = disco
 	})
 }
diff --git a/actors/errors.go b/actors/errors.go
index 97de6f2..7d00f55 100644
--- a/actors/errors.go
+++ b/actors/errors.go
@@ -15,6 +15,7 @@ var (
 	ErrUndefinedActor         = errors.New("actor is not defined")
 	ErrRequestTimeout         = errors.New("request timed out")
 	ErrEmptyBehavior          = errors.New("no behavior defined")
+	ErrRemotingNotEnabled     = errors.New("remoting is not enabled")
 
 	ErrRemoteSendInvalidNode = connect.NewError(connect.CodeFailedPrecondition, errors.New("invalid actor system node"))
 	ErrRemoteActorNotFound   = func(addr string) error {
diff --git a/actors/local_address.go b/actors/local_address.go
deleted file mode 100644
index 8064703..0000000
--- a/actors/local_address.go
+++ /dev/null
@@ -1,153 +0,0 @@
-package actors
-
-import (
-	"bytes"
-	"net/url"
-	"strconv"
-
-	"github.com/pkg/errors"
-)
-
-const (
-	protocol = "goakt"
-)
-
-// LocalAddress represents the physical location under which an Actor can be
-// reached. Examples are local addresses, identified by the ActorSystem’s name,
-// and remote addresses, identified by protocol, host and port.
-type LocalAddress struct {
-	// host is the host address
-	host string
-	// port is the port number
-	port int
-	// system is the actor system name
-	system string
-	// protocol is the protocol
-	protocol string
-}
-
-// NewLocalAddress creates an instance of LocalAddress
-func NewLocalAddress(protocol string, system string, host string, port int) *LocalAddress {
-	return &LocalAddress{
-		host:     host,
-		port:     port,
-		system:   system,
-		protocol: protocol,
-	}
-}
-
-// WithHost sets the hosts of a given LocalAddress and returns a new instance of the address
-func (a *LocalAddress) WithHost(host string) *LocalAddress {
-	return NewLocalAddress(a.Protocol(), a.System(), host, a.Port())
-}
-
-// WithPort sets the port of a given LocalAddress and returns a new instance of the address
-func (a *LocalAddress) WithPort(port int) *LocalAddress {
-	return NewLocalAddress(a.Protocol(), a.System(), a.System(), port)
-}
-
-// WithSystem sets the actor system of a given LocalAddress and returns a new instance of the address
-func (a *LocalAddress) WithSystem(system string) *LocalAddress {
-	return NewLocalAddress(a.Protocol(), system, a.Host(), a.Port())
-}
-
-// WithProtocol sets the protocol of a given LocalAddress and returns a new instance of the address
-func (a *LocalAddress) WithProtocol(protocol string) *LocalAddress {
-	return NewLocalAddress(protocol, a.System(), a.Host(), a.Port())
-}
-
-// Host returns the host
-func (a *LocalAddress) Host() string {
-	return a.host
-}
-
-// Port returns the port number
-func (a *LocalAddress) Port() int {
-	return a.port
-}
-
-// System returns the actor system name
-func (a *LocalAddress) System() string {
-	return a.system
-}
-
-// Protocol returns the protocol
-func (a *LocalAddress) Protocol() string {
-	return a.protocol
-}
-
-// HostPort returns the host and port in the following string format
-// @host:port
-func (a *LocalAddress) HostPort() string {
-	// create a bytes buffer instance
-	buf := bytes.NewBuffer(nil)
-	// write the host value when it is set
-	if len(a.host) > 0 {
-		buf.WriteByte('@')
-		buf.WriteString(a.host)
-	}
-
-	// write the port when the port is set
-	if a.port > 0 {
-		buf.WriteByte(':')
-		buf.WriteString(strconv.Itoa(a.port))
-	}
-
-	// return the constructed string
-	return buf.String()
-}
-
-// String returns the canonical String representation of this LocalAddress formatted as:
-// `protocol://system@host:port`
-func (a *LocalAddress) String() string {
-	// if the protocol is not messages
-	// then panic
-	if a.protocol != protocol {
-		panic("invalid protocol")
-	}
-	// create a bytes buffer instance
-	buf := bytes.NewBuffer(nil)
-	// write the protocol field to bytes buffer
-	buf.WriteString(a.protocol)
-	buf.WriteString("://")
-	buf.WriteString(a.system)
-
-	// write the host to the bytes buffer when it is defined
-	if len(a.host) > 0 {
-		buf.WriteByte('@')
-		buf.WriteString(a.host)
-	}
-
-	// write the port to the bytes buffer when it is set
-	if a.port > 0 {
-		buf.WriteByte(':')
-		buf.WriteString(strconv.Itoa(a.port))
-	}
-
-	// returns the constructed string value
-	return buf.String()
-}
-
-// Parse parses a new LocalAddress from a given string
-func (a *LocalAddress) Parse(address string) *LocalAddress {
-	// let us parse the address and panic in case of error
-	uri, err := url.Parse(address)
-	// panic when there is an error
-	if err != nil {
-		panic(errors.Wrapf(err, "failed to parse the address [%s]", address))
-	}
-
-	// check whether the user info is empty or not
-	// parse the port
-	port, err := strconv.Atoi(uri.Port())
-	// handle the error
-	if err != nil {
-		panic(errors.Wrapf(err, "failed to parse the address [%s]", address))
-	}
-
-	if uri.User == nil {
-		return NewLocalAddress(uri.Scheme, uri.Hostname(), "", port)
-	}
-
-	return NewLocalAddress(uri.Scheme, uri.User.String(), uri.Hostname(), port)
-}
diff --git a/actors/path.go b/actors/path.go
index 76286e9..14318c6 100644
--- a/actors/path.go
+++ b/actors/path.go
@@ -9,8 +9,8 @@ import (
 
 // Path is a unique path to an actor
 type Path struct {
-	// specifies the LocalAddress under which this path can be reached
-	address *LocalAddress
+	// specifies the Address under which this path can be reached
+	address *Address
 	// specifies the name of the actor that this path refers to.
 	name string
 	// specifies the internal unique id of the actor that this path refer to.
@@ -20,7 +20,7 @@ type Path struct {
 }
 
 // NewPath creates an immutable Path
-func NewPath(name string, address *LocalAddress) *Path {
+func NewPath(name string, address *Address) *Path {
 	// create the instance and return it
 	return &Path{
 		address: address,
@@ -30,44 +30,58 @@ func NewPath(name string, address *LocalAddress) *Path {
 }
 
 // Parent returns the parent path
-func (a *Path) Parent() *Path {
-	return a.parent
+func (p *Path) Parent() *Path {
+	return p.parent
 }
 
 // WithParent sets the parent actor path and returns a new path
 // This function is immutable
-func (a *Path) WithParent(parent *Path) *Path {
-	newPath := NewPath(a.name, a.address)
+func (p *Path) WithParent(parent *Path) *Path {
+	newPath := NewPath(p.name, p.address)
 	newPath.parent = parent
 	return newPath
 }
 
 // LocalAddress return the actor path local address
-func (a *Path) LocalAddress() *LocalAddress {
-	return a.address
+func (p *Path) LocalAddress() *Address {
+	// only return the local address when the address is in local scope
+	// otherwise return nil
+	if p.address.IsLocal() {
+		return p.address
+	}
+	return nil
+}
+
+// Address returns the address of the path
+func (p *Path) Address() *Address {
+	return p.address
 }
 
 // Name returns the name of the actor that this path refers to.
-func (a *Path) Name() string {
-	return a.name
+func (p *Path) Name() string {
+	return p.name
 }
 
 // ID returns the internal unique id of the actor that this path refer to.
-func (a *Path) ID() uuid.UUID {
-	return a.id
+func (p *Path) ID() uuid.UUID {
+	return p.id
 }
 
 // String returns the string representation of an actorPath
-func (a *Path) String() string {
-	return fmt.Sprintf("%s/%s", a.address.String(), a.name)
+func (p *Path) String() string {
+	return fmt.Sprintf("%s/%s", p.address.String(), p.name)
 }
 
 // RemoteAddress returns the remote from path
-func (a *Path) RemoteAddress() *pb.Address {
+func (p *Path) RemoteAddress() *pb.Address {
+	// only returns a remote address when we are in a remote scope otherwise return nil
+	if !p.address.IsRemote() {
+		return nil
+	}
 	return &pb.Address{
-		Host: a.LocalAddress().Host(),
-		Port: int32(a.LocalAddress().Port()),
-		Name: a.Name(),
-		Id:   a.ID().String(),
+		Host: p.address.Host(),
+		Port: int32(p.address.Port()),
+		Name: p.Name(),
+		Id:   p.ID().String(),
 	}
 }
diff --git a/actors/pid.go b/actors/pid.go
index 7b12fbf..ded34bb 100644
--- a/actors/pid.go
+++ b/actors/pid.go
@@ -328,7 +328,7 @@ func (p *pid) SpawnChild(ctx context.Context, name string, actor Actor) (PID, er
 	}
 
 	// create the child actor path
-	childActorPath := NewPath(name, p.ActorPath().LocalAddress()).WithParent(p.ActorPath())
+	childActorPath := NewPath(name, p.ActorPath().Address()).WithParent(p.ActorPath())
 
 	// check whether the child actor already exist and just return the PID
 	if cid, ok := p.children.Get(childActorPath); ok {
@@ -547,8 +547,8 @@ func (p *pid) RemoteTell(ctx context.Context, to *pb.Address, message proto.Mess
 
 	// construct the from address
 	sender := &pb.Address{
-		Host: p.ActorPath().LocalAddress().Host(),
-		Port: int32(p.ActorPath().LocalAddress().Port()),
+		Host: p.ActorPath().Address().Host(),
+		Port: int32(p.ActorPath().Address().Port()),
 		Name: p.ActorPath().Name(),
 		Id:   p.ActorPath().ID().String(),
 	}
@@ -817,7 +817,7 @@ func (p *pid) stop(ctx context.Context) {
 	// signal we are shutting down to stop processing public
 	p.shutdownSignal <- Unit{}
 	// add some logging
-	p.logger.Infof("Remaining public in the mailbox have been processed for actor=%s", p.ActorPath().String())
+	p.logger.Infof("Remaining messages in the mailbox have been processed for actor=%s", p.ActorPath().String())
 	// stop the ticker
 	ticker.Stop()
 }
diff --git a/cluster/cluster.go b/cluster/cluster.go
index 328d7f8..872fd2e 100644
--- a/cluster/cluster.go
+++ b/cluster/cluster.go
@@ -45,6 +45,7 @@ type Cluster struct {
 	etcdNode          *embed.Node
 	dataDir           string
 	peersListenerChan chan struct{}
+	nodeHost          string
 }
 
 // New creates an instance of Cluster
@@ -201,8 +202,6 @@ func (c *Cluster) Start(ctx context.Context) error {
 		return err
 	}
 
-	// promote the node to a voter
-
 	// let us build the KV store connection endpoints
 	// create the instance of the distributed store and set it
 	c.store, err = kvstore.New(kvstore.NewConfig(c.logger, c.etcdNode.Client()))
@@ -225,6 +224,9 @@ func (c *Cluster) Start(ctx context.Context) error {
 		return c.Stop()
 	}
 
+	// set the nodeHost
+	c.nodeHost = hostNode.host
+
 	// start listening to the discovery events
 	go c.handleClusterEvents(discoEvents)
 
@@ -250,6 +252,11 @@ func (c *Cluster) Stop() error {
 	return nil
 }
 
+// NodeHost returns the cluster node Host
+func (c *Cluster) NodeHost() string {
+	return c.nodeHost
+}
+
 // PutActor replicates onto the cluster the metadata of an actor
 func (c *Cluster) PutActor(ctx context.Context, actor *goaktpb.WireActor) error {
 	// create a cancellation context of 1 second timeout
diff --git a/examples/actor-cluster/k8s/Makefile b/examples/actor-cluster/k8s/Makefile
index 0c43d05..c810505 100644
--- a/examples/actor-cluster/k8s/Makefile
+++ b/examples/actor-cluster/k8s/Makefile
@@ -1,8 +1,8 @@
 .PHONY: cluster-down
-example-rm:
-	kubectl delete -f ./k8s.yml
+cluster-down:
+	kubectl delete -f ./k8s.yaml
 
 .PHONY: cluster-up
-example-up:
+cluster-up:
 	minikube image load --overwrite=true accounts:dev
-	kubectl apply -f ./k8s.yml
+	kubectl apply -f ./k8s.yaml
diff --git a/examples/actor-cluster/k8s/cmd/run.go b/examples/actor-cluster/k8s/cmd/run.go
index 9fd3cf9..baf1d36 100644
--- a/examples/actor-cluster/k8s/cmd/run.go
+++ b/examples/actor-cluster/k8s/cmd/run.go
@@ -2,7 +2,6 @@ package cmd
 
 import (
 	"context"
-	"fmt"
 	"os"
 	"os/signal"
 	"syscall"
@@ -17,7 +16,7 @@ import (
 )
 
 const (
-	nodePort           = 9000
+	remotingPort       = 9000
 	accountServicePort = 50051
 	nodeHost           = "0.0.0.0"
 	namespace          = "default"
@@ -50,12 +49,10 @@ var runCmd = &cobra.Command{
 		// create the actor system configuration
 		config, err := goakt.NewConfig(
 			actorSystemName,
-			fmt.Sprintf("%s:%d", nodeHost, nodePort),
 			goakt.WithPassivationDisabled(), // set big passivation time
 			goakt.WithLogger(logger),
 			goakt.WithActorInitMaxRetries(3),
-			goakt.WithRemoting(),
-			goakt.WithClustering(disco))
+			goakt.WithClustering(disco, remotingPort))
 		// handle the error
 		if err != nil {
 			logger.Panic(err)
diff --git a/examples/actor-observability/main.go b/examples/actor-observability/main.go
index 536ba23..a6216fc 100644
--- a/examples/actor-observability/main.go
+++ b/examples/actor-observability/main.go
@@ -16,7 +16,6 @@ import (
 	"go.opentelemetry.io/otel"
 	"go.opentelemetry.io/otel/exporters/prometheus"
 	"go.opentelemetry.io/otel/exporters/stdout/stdouttrace"
-	"go.opentelemetry.io/otel/metric/global"
 	"go.opentelemetry.io/otel/sdk/metric"
 	"go.opentelemetry.io/otel/sdk/resource"
 	sdktrace "go.opentelemetry.io/otel/sdk/trace"
@@ -58,7 +57,8 @@ func initMeter() {
 			serviceName,
 		)),
 	)
-	global.SetMeterProvider(meterProvider)
+
+	otel.SetMeterProvider(meterProvider)
 
 	http.Handle("/metrics", promhttp.Handler())
 	go func() {
@@ -76,7 +76,7 @@ func main() {
 	logger := log.DefaultLogger
 
 	// create the actor system configuration. kindly in real-life application handle the error
-	config, _ := goakt.NewConfig("SampleActorSystem", "127.0.0.1:0",
+	config, _ := goakt.NewConfig("SampleActorSystem",
 		goakt.WithExpireActorAfter(10*time.Second), // set big passivation time
 		goakt.WithLogger(logger),
 		goakt.WithActorInitMaxRetries(3))
@@ -128,7 +128,7 @@ func (p *PingActor) PreStart(ctx context.Context) error {
 	// set the log
 	p.logger = log.DefaultLogger
 	p.count = atomic.NewInt32(0)
-	p.logger.Info("About to Start")
+	p.logger.Info("PingActor is about to Start")
 	return nil
 }
 
@@ -148,8 +148,8 @@ func (p *PingActor) Receive(ctx goakt.ReceiveContext) {
 }
 
 func (p *PingActor) PostStop(ctx context.Context) error {
-	p.logger.Info("About to stop")
-	p.logger.Infof("Processed=%d messages", p.count.Load())
+	p.logger.Info("PingActor is about to stop")
+	p.logger.Infof("PingActor has processed=%d messages", p.count.Load())
 	return nil
 }
 
@@ -168,7 +168,7 @@ func (p *PongActor) PreStart(ctx context.Context) error {
 	// set the log
 	p.logger = log.DefaultLogger
 	p.count = atomic.NewInt32(0)
-	p.logger.Info("About to Start")
+	p.logger.Info("PongActor is about to Start")
 	return nil
 }
 
@@ -187,7 +187,7 @@ func (p *PongActor) Receive(ctx goakt.ReceiveContext) {
 }
 
 func (p *PongActor) PostStop(ctx context.Context) error {
-	p.logger.Info("About to stop")
-	p.logger.Infof("Processed=%d messages", p.count.Load())
+	p.logger.Info("PongActor is about to stop")
+	p.logger.Infof("PongActor has processed=%d messages", p.count.Load())
 	return nil
 }
diff --git a/examples/actor-receive/main.go b/examples/actor-receive/main.go
index 01c8c77..533f1a4 100644
--- a/examples/actor-receive/main.go
+++ b/examples/actor-receive/main.go
@@ -20,7 +20,7 @@ func main() {
 	// use the messages default log. real-life implement the log interface`
 	logger := log.DefaultLogger
 	// create the actor system configuration. kindly in real-life application handle the error
-	config, _ := goakt.NewConfig("SampleActorSystem", "127.0.0.1:0",
+	config, _ := goakt.NewConfig("SampleActorSystem",
 		goakt.WithExpireActorAfter(10*time.Second),
 		goakt.WithLogger(logger),
 		goakt.WithActorInitMaxRetries(3))
diff --git a/examples/actor-to-actor/main.go b/examples/actor-to-actor/main.go
index b49d21a..5506a22 100644
--- a/examples/actor-to-actor/main.go
+++ b/examples/actor-to-actor/main.go
@@ -22,7 +22,7 @@ func main() {
 	logger := log.DefaultLogger
 
 	// create the actor system configuration. kindly in real-life application handle the error
-	config, _ := goakt.NewConfig("SampleActorSystem", "127.0.0.1:0",
+	config, _ := goakt.NewConfig("SampleActorSystem",
 		goakt.WithExpireActorAfter(10*time.Second), // set big passivation time
 		goakt.WithLogger(logger),
 		goakt.WithActorInitMaxRetries(3))
@@ -79,7 +79,7 @@ func (p *PingActor) PreStart(ctx context.Context) error {
 	defer p.mu.Unlock()
 	p.logger = log.DefaultLogger
 	p.count = atomic.NewInt32(0)
-	p.logger.Info("About to Start")
+	p.logger.Info("PingActor is about to Start")
 	return nil
 }
 
@@ -99,8 +99,8 @@ func (p *PingActor) Receive(ctx goakt.ReceiveContext) {
 }
 
 func (p *PingActor) PostStop(ctx context.Context) error {
-	p.logger.Info("About to stop")
-	p.logger.Infof("Processed=%d messages", p.count.Load())
+	p.logger.Info("PingActor is about to stop")
+	p.logger.Infof("PingActor has processed=%d messages", p.count.Load())
 	return nil
 }
 
@@ -124,7 +124,7 @@ func (p *PongActor) PreStart(ctx context.Context) error {
 	defer p.mu.Unlock()
 	p.logger = log.DefaultLogger
 	p.count = atomic.NewInt32(0)
-	p.logger.Info("About to Start")
+	p.logger.Info("PongActor is about to Start")
 	return nil
 }
 
@@ -143,7 +143,7 @@ func (p *PongActor) Receive(ctx goakt.ReceiveContext) {
 }
 
 func (p *PongActor) PostStop(ctx context.Context) error {
-	p.logger.Info("About to stop")
-	p.logger.Infof("Processed=%d messages", p.count.Load())
+	p.logger.Info("PongActor is about to stop")
+	p.logger.Infof("PongActor has processed=%d messages", p.count.Load())
 	return nil
 }
diff --git a/examples/remoting/ping/main.go b/examples/remoting/ping/main.go
index 11e1811..97802ab 100644
--- a/examples/remoting/ping/main.go
+++ b/examples/remoting/ping/main.go
@@ -6,6 +6,7 @@ import (
 	"os"
 	"os/signal"
 	"syscall"
+	"time"
 
 	goakt "github.com/tochemey/goakt/actors"
 	samplepb "github.com/tochemey/goakt/examples/protos/pb/v1"
@@ -28,11 +29,10 @@ func main() {
 
 	// create the actor system configuration. kindly in real-life application handle the error
 	config, _ := goakt.NewConfig("SampleActorSystem",
-		fmt.Sprintf("%s:%d", host, port),
 		goakt.WithPassivationDisabled(), // set big passivation time
 		goakt.WithLogger(logger),
 		goakt.WithActorInitMaxRetries(3),
-		goakt.WithRemoting())
+		goakt.WithRemoting(host, port))
 
 	// create the actor system. kindly in real-life application handle the error
 	actorSystem, _ := goakt.NewActorSystem(config)
@@ -44,12 +44,15 @@ func main() {
 	pingActor := actorSystem.StartActor(ctx, "Ping", NewPingActor())
 
 	// start the conversation
-	_ = pingActor.RemoteTell(ctx, &pb.Address{
-		Host: host,
-		Port: 9001,
-		Name: "Pong",
-		Id:   "",
-	}, new(samplepb.Ping))
+	timer := time.AfterFunc(time.Second, func() {
+		_ = pingActor.RemoteTell(ctx, &pb.Address{
+			Host: host,
+			Port: 9001,
+			Name: "Pong",
+			Id:   "",
+		}, new(samplepb.Ping))
+	})
+	defer timer.Stop()
 
 	// capture ctrl+c
 	interruptSignal := make(chan os.Signal, 1)
diff --git a/examples/remoting/pong/main.go b/examples/remoting/pong/main.go
index a098d9a..3bad3be 100644
--- a/examples/remoting/pong/main.go
+++ b/examples/remoting/pong/main.go
@@ -2,7 +2,6 @@ package main
 
 import (
 	"context"
-	"fmt"
 	"os"
 	"os/signal"
 	"syscall"
@@ -27,11 +26,11 @@ func main() {
 	logger := log.DefaultLogger
 
 	// create the actor system configuration. kindly in real-life application handle the error
-	config, _ := goakt.NewConfig("SampleActorSystem", fmt.Sprintf("%s:%d", host, port),
+	config, _ := goakt.NewConfig("SampleActorSystem",
 		goakt.WithPassivationDisabled(), // set big passivation time
 		goakt.WithLogger(logger),
 		goakt.WithActorInitMaxRetries(3),
-		goakt.WithRemoting())
+		goakt.WithRemoting(host, port))
 
 	// create the actor system. kindly in real-life application handle the error
 	actorSystem, _ := goakt.NewActorSystem(config)
diff --git a/go.mod b/go.mod
index 946c7f1..455a69a 100644
--- a/go.mod
+++ b/go.mod
@@ -4,7 +4,7 @@ go 1.20
 
 require (
 	github.com/bufbuild/connect-go v1.7.0
-	github.com/bufbuild/connect-opentelemetry-go v0.2.0
+	github.com/bufbuild/connect-opentelemetry-go v0.3.0
 	github.com/cenkalti/backoff v2.2.1+incompatible
 	github.com/coreos/etcd v3.3.27+incompatible
 	github.com/deckarep/golang-set/v2 v2.3.0
@@ -17,27 +17,27 @@ require (
 	github.com/pkg/errors v0.9.1
 	github.com/prometheus/client_golang v1.15.1
 	github.com/spf13/cobra v1.7.0
-	github.com/stretchr/testify v1.8.2
+	github.com/stretchr/testify v1.8.3
 	go.etcd.io/etcd/api/v3 v3.5.9
 	go.etcd.io/etcd/client/v3 v3.5.9
 	go.etcd.io/etcd/server/v3 v3.5.9
-	go.opentelemetry.io/otel v1.15.1
-	go.opentelemetry.io/otel/exporters/prometheus v0.38.1
-	go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.15.1
-	go.opentelemetry.io/otel/metric v0.38.1
-	go.opentelemetry.io/otel/sdk v1.15.1
-	go.opentelemetry.io/otel/sdk/metric v0.38.1
-	go.opentelemetry.io/otel/trace v1.15.1
+	go.opentelemetry.io/otel v1.16.0
+	go.opentelemetry.io/otel/exporters/prometheus v0.39.0
+	go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0
+	go.opentelemetry.io/otel/metric v1.16.0
+	go.opentelemetry.io/otel/sdk v1.16.0
+	go.opentelemetry.io/otel/sdk/metric v0.39.0
+	go.opentelemetry.io/otel/trace v1.16.0
 	go.uber.org/atomic v1.11.0
 	go.uber.org/goleak v1.2.1
 	go.uber.org/zap v1.24.0
-	golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc
+	golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1
 	golang.org/x/net v0.10.0
 	google.golang.org/grpc v1.55.0
 	google.golang.org/protobuf v1.30.0
-	k8s.io/api v0.27.1
-	k8s.io/apimachinery v0.27.1
-	k8s.io/client-go v0.27.1
+	k8s.io/api v0.27.2
+	k8s.io/apimachinery v0.27.2
+	k8s.io/client-go v0.27.2
 )
 
 require (
@@ -77,8 +77,8 @@ require (
 	github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
 	github.com/pmezard/go-difflib v1.0.0 // indirect
 	github.com/prometheus/client_model v0.4.0 // indirect
-	github.com/prometheus/common v0.43.0 // indirect
-	github.com/prometheus/procfs v0.9.0 // indirect
+	github.com/prometheus/common v0.44.0 // indirect
+	github.com/prometheus/procfs v0.10.0 // indirect
 	github.com/sirupsen/logrus v1.9.2 // indirect
 	github.com/soheilhy/cmux v0.1.5 // indirect
 	github.com/spf13/pflag v1.0.5 // indirect
@@ -90,10 +90,10 @@ require (
 	go.etcd.io/etcd/client/v2 v2.305.9 // indirect
 	go.etcd.io/etcd/pkg/v3 v3.5.9 // indirect
 	go.etcd.io/etcd/raft/v3 v3.5.9 // indirect
-	go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.41.1 // indirect
-	go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.15.1 // indirect
-	go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.15.1 // indirect
-	go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.15.1 // indirect
+	go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0 // indirect
+	go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.16.0 // indirect
+	go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.16.0 // indirect
+	go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.16.0 // indirect
 	go.opentelemetry.io/proto/otlp v0.19.0 // indirect
 	go.uber.org/multierr v1.11.0 // indirect
 	golang.org/x/crypto v0.9.0 // indirect
@@ -111,7 +111,7 @@ require (
 	gopkg.in/yaml.v2 v2.4.0 // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
 	k8s.io/klog/v2 v2.100.1 // indirect
-	k8s.io/kube-openapi v0.0.0-20230515203736-54b630e78af5 // indirect
+	k8s.io/kube-openapi v0.0.0-20230523194449-df37dd07aa00 // indirect
 	k8s.io/utils v0.0.0-20230505201702-9f6742963106 // indirect
 	sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
 	sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
diff --git a/go.sum b/go.sum
index 741052d..81aa15e 100644
--- a/go.sum
+++ b/go.sum
@@ -44,8 +44,8 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
 github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
 github.com/bufbuild/connect-go v1.7.0 h1:MGp82v7SCza+3RhsVhV7aMikwxvI3ZfD72YiGt8FYJo=
 github.com/bufbuild/connect-go v1.7.0/go.mod h1:GmMJYR6orFqD0Y6ZgX8pwQ8j9baizDrIQMm1/a6LnHk=
-github.com/bufbuild/connect-opentelemetry-go v0.2.0 h1:GRziom+3DSYHv0bWGARhgD8WXYWnd8NDiHNVqK2sSEg=
-github.com/bufbuild/connect-opentelemetry-go v0.2.0/go.mod h1:I+IU6e9kQZ0orGg0JpdLNWLtSROe3GAUXvuQBT+zBSw=
+github.com/bufbuild/connect-opentelemetry-go v0.3.0 h1:AuZi3asTDKmjGtd2aqpyP4p5QvBFG/YEaHopViLatnk=
+github.com/bufbuild/connect-opentelemetry-go v0.3.0/go.mod h1:r1ppyTtu1EWeRodk4Q/JbyQhIWtO7eR3GoRDzjeEcNU=
 github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
 github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4=
 github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
@@ -257,10 +257,10 @@ github.com/prometheus/client_golang v1.15.1/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt
 github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
 github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY=
 github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU=
-github.com/prometheus/common v0.43.0 h1:iq+BVjvYLei5f27wiuNiB1DN6DYQkp1c8Bx0Vykh5us=
-github.com/prometheus/common v0.43.0/go.mod h1:NCvr5cQIh3Y/gy73/RdVtC9r8xxrxwJnB+2lB3BxrFc=
-github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI=
-github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY=
+github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY=
+github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY=
+github.com/prometheus/procfs v0.10.0 h1:UkG7GPYkO4UZyLnyXjaWYcgOSONqwdBqFUT95ugmt6I=
+github.com/prometheus/procfs v0.10.0/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM=
 github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
 github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
 github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
@@ -290,8 +290,8 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
 github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
 github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
-github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
-github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
+github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
+github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
 github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75 h1:6fotK7otjonDflCTK0BCfls4SPy3NcCVb5dqqmbRknE=
 github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75/go.mod h1:KO6IkyS8Y3j8OdNO85qEYBsRPuteD+YciPomcXdrMnk=
 github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
@@ -324,28 +324,28 @@ go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
 go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
 go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
 go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
-go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.41.1 h1:Ei1FUQ5CbSNkl2o/XAiksXSyQNAeJBX3ivqJpJ254Ak=
-go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.41.1/go.mod h1:f7TOPTlEcliCBlOYPuNnZTuND71MVTAoINWIt1SmP/c=
-go.opentelemetry.io/otel v1.15.1 h1:3Iwq3lfRByPaws0f6bU3naAqOR1n5IeDWd9390kWHa8=
-go.opentelemetry.io/otel v1.15.1/go.mod h1:mHHGEHVDLal6YrKMmk9LqC4a3sF5g+fHfrttQIB1NTc=
-go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.15.1 h1:XYDQtNzdb2T4uM1pku2m76eSMDJgqhJ+6KzkqgQBALc=
-go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.15.1/go.mod h1:uOTV75+LOzV+ODmL8ahRLWkFA3eQcSC2aAsbxIu4duk=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.15.1 h1:tyoeaUh8REKay72DVYsSEBYV18+fGONe+YYPaOxgLoE=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.15.1/go.mod h1:HUSnrjQQ19KX9ECjpQxufsF+3ioD3zISPMlauTPZu2g=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.15.1 h1:pIfoG5IAZFzp9EUlJzdSkpUwpaUAAnD+Ru1nBLTACIQ=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.15.1/go.mod h1:poNKBqF5+nR/6ke2oGTDjHfksrsHDOHXAl2g4+9ONsY=
-go.opentelemetry.io/otel/exporters/prometheus v0.38.1 h1:GwalIvFIx91qIA8qyAyqYj9lql5Ba2Oxj/jDG6+3UoU=
-go.opentelemetry.io/otel/exporters/prometheus v0.38.1/go.mod h1:6K7aBvWHXRUcNYFSj6Hi5hHwzA1jYflG/T8snrX4dYM=
-go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.15.1 h1:2PunuO5SbkN5MhCbuHCd3tC6qrcaj+uDAkX/qBU5BAs=
-go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.15.1/go.mod h1:q8+Tha+5LThjeSU8BW93uUC5w5/+DnYHMKBMpRCsui0=
-go.opentelemetry.io/otel/metric v0.38.1 h1:2MM7m6wPw9B8Qv8iHygoAgkbejed59uUR6ezR5T3X2s=
-go.opentelemetry.io/otel/metric v0.38.1/go.mod h1:FwqNHD3I/5iX9pfrRGZIlYICrJv0rHEUl2Ln5vdIVnQ=
-go.opentelemetry.io/otel/sdk v1.15.1 h1:5FKR+skgpzvhPQHIEfcwMYjCBr14LWzs3uSqKiQzETI=
-go.opentelemetry.io/otel/sdk v1.15.1/go.mod h1:8rVtxQfrbmbHKfqzpQkT5EzZMcbMBwTzNAggbEAM0KA=
-go.opentelemetry.io/otel/sdk/metric v0.38.1 h1:EkO5wI4NT/fUaoPMGc0fKV28JaWe7q4vfVpEVasGb+8=
-go.opentelemetry.io/otel/sdk/metric v0.38.1/go.mod h1:Rn4kSXFF9ZQZ5lL1pxQjCbK4seiO+U7s0ncmIFJaj34=
-go.opentelemetry.io/otel/trace v1.15.1 h1:uXLo6iHJEzDfrNC0L0mNjItIp06SyaBQxu5t3xMlngY=
-go.opentelemetry.io/otel/trace v1.15.1/go.mod h1:IWdQG/5N1x7f6YUlmdLeJvH9yxtuJAfc4VW5Agv9r/8=
+go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0 h1:ZOLJc06r4CB42laIXg/7udr0pbZyuAihN10A/XuiQRY=
+go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0/go.mod h1:5z+/ZWJQKXa9YT34fQNx5K8Hd1EoIhvtUygUQPqEOgQ=
+go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s=
+go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4=
+go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.16.0 h1:t4ZwRPU+emrcvM2e9DHd0Fsf0JTPVcbfa/BhTDF03d0=
+go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.16.0/go.mod h1:vLarbg68dH2Wa77g71zmKQqlQ8+8Rq3GRG31uc0WcWI=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.16.0 h1:cbsD4cUcviQGXdw8+bo5x2wazq10SKz8hEbtCRPcU78=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.16.0/go.mod h1:JgXSGah17croqhJfhByOLVY719k1emAXC8MVhCIJlRs=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.16.0 h1:TVQp/bboR4mhZSav+MdgXB8FaRho1RC8UwVn3T0vjVc=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.16.0/go.mod h1:I33vtIe0sR96wfrUcilIzLoA3mLHhRmz9S9Te0S3gDo=
+go.opentelemetry.io/otel/exporters/prometheus v0.39.0 h1:whAaiHxOatgtKd+w0dOi//1KUxj3KoPINZdtDaDj3IA=
+go.opentelemetry.io/otel/exporters/prometheus v0.39.0/go.mod h1:4jo5Q4CROlCpSPsXLhymi+LYrDXd2ObU5wbKayfZs7Y=
+go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0 h1:+XWJd3jf75RXJq29mxbuXhCXFDG3S3R4vBUeSI2P7tE=
+go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0/go.mod h1:hqgzBPTf4yONMFgdZvL/bK42R/iinTyVQtiWihs3SZc=
+go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo=
+go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4=
+go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE=
+go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4=
+go.opentelemetry.io/otel/sdk/metric v0.39.0 h1:Kun8i1eYf48kHH83RucG93ffz0zGV1sh46FAScOTuDI=
+go.opentelemetry.io/otel/sdk/metric v0.39.0/go.mod h1:piDIRgjcK7u0HCL5pCA4e74qpK/jk3NiUoAHATVAmiI=
+go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs=
+go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0=
 go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
 go.opentelemetry.io/proto/otlp v0.19.0 h1:IVN6GR+mhC4s5yfcTbmzHYODqvWAp3ZedA2SJPI1Nnw=
 go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
@@ -378,8 +378,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
 golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
 golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
-golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc h1:mCRnTeVUjcrhlRmO0VK8a6k6Rrf6TF9htwo2pJVSjIU=
-golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
+golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc=
+golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
 golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
 golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
 golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -677,16 +677,16 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
 honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
 honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
 honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
-k8s.io/api v0.27.1 h1:Z6zUGQ1Vd10tJ+gHcNNNgkV5emCyW+v2XTmn+CLjSd0=
-k8s.io/api v0.27.1/go.mod h1:z5g/BpAiD+f6AArpqNjkY+cji8ueZDU/WV1jcj5Jk4E=
-k8s.io/apimachinery v0.27.1 h1:EGuZiLI95UQQcClhanryclaQE6xjg1Bts6/L3cD7zyc=
-k8s.io/apimachinery v0.27.1/go.mod h1:5ikh59fK3AJ287GUvpUsryoMFtH9zj/ARfWCo3AyXTM=
-k8s.io/client-go v0.27.1 h1:oXsfhW/qncM1wDmWBIuDzRHNS2tLhK3BZv512Nc59W8=
-k8s.io/client-go v0.27.1/go.mod h1:f8LHMUkVb3b9N8bWturc+EDtVVVwZ7ueTVquFAJb2vA=
+k8s.io/api v0.27.2 h1:+H17AJpUMvl+clT+BPnKf0E3ksMAzoBBg7CntpSuADo=
+k8s.io/api v0.27.2/go.mod h1:ENmbocXfBT2ADujUXcBhHV55RIT31IIEvkntP6vZKS4=
+k8s.io/apimachinery v0.27.2 h1:vBjGaKKieaIreI+oQwELalVG4d8f3YAMNpWLzDXkxeg=
+k8s.io/apimachinery v0.27.2/go.mod h1:XNfZ6xklnMCOGGFNqXG7bUrQCoR04dh/E7FprV6pb+E=
+k8s.io/client-go v0.27.2 h1:vDLSeuYvCHKeoQRhCXjxXO45nHVv2Ip4Fe0MfioMrhE=
+k8s.io/client-go v0.27.2/go.mod h1:tY0gVmUsHrAmjzHX9zs7eCjxcBsf8IiNe7KQ52biTcQ=
 k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg=
 k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
-k8s.io/kube-openapi v0.0.0-20230515203736-54b630e78af5 h1:azYPdzztXxPSa8wb+hksEKayiz0o+PPisO/d+QhWnoo=
-k8s.io/kube-openapi v0.0.0-20230515203736-54b630e78af5/go.mod h1:kzo02I3kQ4BTtEfVLaPbjvCkX97YqGve33wzlb3fofQ=
+k8s.io/kube-openapi v0.0.0-20230523194449-df37dd07aa00 h1:Sb9XaC5itZdDOVp7CTFhW8cxWIuRryoU4Oq6U8eEeOk=
+k8s.io/kube-openapi v0.0.0-20230523194449-df37dd07aa00/go.mod h1:kzo02I3kQ4BTtEfVLaPbjvCkX97YqGve33wzlb3fofQ=
 k8s.io/utils v0.0.0-20230505201702-9f6742963106 h1:EObNQ3TW2D+WptiYXlApGNLVy0zm/JIBVY9i+M4wpAU=
 k8s.io/utils v0.0.0-20230505201702-9f6742963106/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
 rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
diff --git a/pkg/telemetry/telemetry.go b/pkg/telemetry/telemetry.go
index 90049f9..2106d5f 100644
--- a/pkg/telemetry/telemetry.go
+++ b/pkg/telemetry/telemetry.go
@@ -3,7 +3,6 @@ package telemetry
 import (
 	"go.opentelemetry.io/otel"
 	"go.opentelemetry.io/otel/metric"
-	metricglobal "go.opentelemetry.io/otel/metric/global"
 	"go.opentelemetry.io/otel/trace"
 )
 
@@ -33,7 +32,7 @@ func New(options ...Option) *Telemetry {
 	// create a config instance
 	telemetry := &Telemetry{
 		TracerProvider: otel.GetTracerProvider(),
-		MeterProvider:  metricglobal.MeterProvider(),
+		MeterProvider:  otel.GetMeterProvider(),
 	}
 
 	// apply the various options
diff --git a/readme.md b/readme.md
index 521c1bf..3fe3665 100644
--- a/readme.md
+++ b/readme.md
@@ -120,7 +120,7 @@ func main() {
   // use the messages default log. real-life implement the log interface`
   logger := log.DefaultLogger
   // create the actor system configuration. kindly in real-life application handle the error
-  config, _ := goakt.NewConfig("SampleActorSystem", "127.0.0.1:0",
+  config, _ := goakt.NewConfig("SampleActorSystem",
     goakt.WithExpireActorAfter(10*time.Second),
     goakt.WithLogger(logger),
     goakt.WithActorInitMaxRetries(3))
@@ -148,7 +148,7 @@ func main() {
   <-interruptSignal
 
   // log some stats
-  logger.Infof("Actor=%s has processed %d public in %s", actor.ActorPath().String(), actor.ReceivedCount(ctx), time.Since(startTime))
+  logger.Infof("Actor=%s has processed %d messages in %s", actor.ActorPath().String(), actor.ReceivedCount(ctx), time.Since(startTime))
 
   // stop the actor system
   _ = actorSystem.Stop(ctx)
@@ -175,14 +175,14 @@ func (p *Pinger) PreStart(ctx context.Context) error {
   defer p.mu.Unlock()
   p.logger = log.DefaultLogger
   p.count = atomic.NewInt32(0)
-  p.logger.Info("About to Start")
+  p.logger.Info("Pinger is about to Start")
   return nil
 }
 
 func (p *Pinger) Receive(ctx goakt.ReceiveContext) {
   switch ctx.Message().(type) {
   case *samplepb.Ping:
-    p.logger.Info("received Ping")
+    p.logger.Info("Pinger received Ping")
     p.count.Add(1)
   default:
     p.logger.Panic(goakt.ErrUnhandled)
@@ -190,8 +190,8 @@ func (p *Pinger) Receive(ctx goakt.ReceiveContext) {
 }
 
 func (p *Pinger) PostStop(ctx context.Context) error {
-  p.logger.Info("About to stop")
-  p.logger.Infof("Processed=%d public", p.count.Load())
+  p.logger.Info("Pinger is about to stop")
+  p.logger.Infof("Processed=%d messages", p.count.Load())
   return nil
 }
 ```


Test patch:
diff --git a/actors/actor_system_test.go b/actors/actor_system_test.go
index bc1dca3..971bded 100644
--- a/actors/actor_system_test.go
+++ b/actors/actor_system_test.go
@@ -11,7 +11,7 @@ import (
 
 func TestActorSystem(t *testing.T) {
 	t.Run("With Defaults", func(t *testing.T) {
-		cfg, err := NewConfig("testSys", "localhost:0", WithLogger(log.DiscardLogger))
+		cfg, err := NewConfig("testSys", WithLogger(log.DiscardLogger))
 		require.NoError(t, err)
 		assert.NotNil(t, cfg)
 
@@ -23,7 +23,6 @@ func TestActorSystem(t *testing.T) {
 		assert.True(t, ok)
 		assert.Equal(t, "testSys", actorSys.Name())
 		assert.Empty(t, actorSys.Actors())
-		assert.Equal(t, "localhost:0", actorSys.NodeAddr())
 	})
 	t.Run("With Missing Config", func(t *testing.T) {
 		sys, err := NewActorSystem(nil)
@@ -33,7 +32,7 @@ func TestActorSystem(t *testing.T) {
 	})
 	t.Run("With StartActor an actor when not started", func(t *testing.T) {
 		ctx := context.TODO()
-		cfg, _ := NewConfig("testSys", "localhost:0", WithLogger(log.DiscardLogger))
+		cfg, _ := NewConfig("testSys", WithLogger(log.DiscardLogger))
 		sys, _ := NewActorSystem(cfg)
 		actor := NewTestActor()
 		actorRef := sys.StartActor(ctx, "Test", actor)
@@ -41,7 +40,7 @@ func TestActorSystem(t *testing.T) {
 	})
 	t.Run("With StartActor an actor when started", func(t *testing.T) {
 		ctx := context.TODO()
-		cfg, _ := NewConfig("testSys", "localhost:0", WithLogger(log.DiscardLogger))
+		cfg, _ := NewConfig("testSys", WithLogger(log.DiscardLogger))
 		sys, _ := NewActorSystem(cfg)
 
 		// start the actor system
@@ -56,7 +55,7 @@ func TestActorSystem(t *testing.T) {
 	})
 	t.Run("With StartActor an actor already exist", func(t *testing.T) {
 		ctx := context.TODO()
-		cfg, _ := NewConfig("test", "localhost:0", WithLogger(log.DiscardLogger))
+		cfg, _ := NewConfig("test", WithLogger(log.DiscardLogger))
 		sys, _ := NewActorSystem(cfg)
 
 		// start the actor system
diff --git a/actors/address_test.go b/actors/address_test.go
new file mode 100644
index 0000000..ab0c3aa
--- /dev/null
+++ b/actors/address_test.go
@@ -0,0 +1,56 @@
+package actors
+
+import (
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+)
+
+func TestAddress(t *testing.T) {
+	t.Run("testCase1", func(t *testing.T) {
+		expected := "goakt://sys@host:1234"
+		addr := NewAddress(protocol, "sys", "host", 1234)
+		assert.False(t, addr.IsLocal())
+		assert.True(t, addr.IsRemote())
+		assert.Equal(t, "host:1234", addr.HostPort())
+		assert.Equal(t, "host", addr.Host())
+		assert.EqualValues(t, 1234, addr.Port())
+		assert.Equal(t, expected, addr.String())
+	})
+	t.Run("testCase2", func(t *testing.T) {
+		expected := "goakt://sys@"
+		addr := NewAddress(protocol, "sys", "", -1)
+		assert.False(t, addr.IsRemote())
+		assert.True(t, addr.IsLocal())
+		assert.Equal(t, expected, addr.String())
+		actual, err := addr.WithHost("localhost")
+		require.Error(t, err)
+		assert.EqualError(t, err, ErrLocalAddress.Error())
+		assert.Nil(t, actual)
+	})
+	t.Run("testCase3", func(t *testing.T) {
+		expected := "goakt://sys@host:1234"
+		addr := NewAddress(protocol, "sys", "host", 1234)
+		assert.False(t, addr.IsLocal())
+		assert.True(t, addr.IsRemote())
+		assert.Equal(t, "host:1234", addr.HostPort())
+		assert.Equal(t, "host", addr.Host())
+		assert.EqualValues(t, 1234, addr.Port())
+		assert.Equal(t, expected, addr.String())
+
+		// change the host
+		actual, err := addr.WithHost("localhost")
+		require.NoError(t, err)
+		expected = "goakt://sys@localhost:1234"
+		assert.False(t, actual.IsLocal())
+		assert.True(t, actual.IsRemote())
+		assert.Equal(t, "localhost:1234", actual.HostPort())
+		assert.Equal(t, "localhost", actual.Host())
+		assert.EqualValues(t, 1234, actual.Port())
+		assert.Equal(t, expected, actual.String())
+
+		assert.False(t, cmp.Equal(addr, actual, cmp.AllowUnexported(Address{})))
+	})
+}
diff --git a/actors/config_test.go b/actors/config_test.go
index c2f042d..06abdfd 100644
--- a/actors/config_test.go
+++ b/actors/config_test.go
@@ -11,7 +11,7 @@ import (
 
 func TestConfig(t *testing.T) {
 	t.Run("WithValidConfig", func(t *testing.T) {
-		cfg, err := NewConfig("testSys", "localhost:0")
+		cfg, err := NewConfig("testSys")
 		require.NoError(t, err)
 		assert.NotNil(t, cfg)
 		assert.EqualValues(t, 100*time.Millisecond, cfg.ReplyTimeout())
@@ -19,19 +19,13 @@ func TestConfig(t *testing.T) {
 		assert.EqualValues(t, 5, cfg.ActorInitMaxRetries())
 		assert.Equal(t, log.DefaultLogger, cfg.Logger())
 		assert.Equal(t, "testSys", cfg.Name())
-		assert.Equal(t, "localhost:0", cfg.NodeHostAndPort())
 	})
 	t.Run("WithEmptyName", func(t *testing.T) {
-		cfg, err := NewConfig("", "localhost:0")
+		cfg, err := NewConfig("")
 		require.Error(t, err)
 		assert.EqualError(t, err, ErrNameRequired.Error())
 		assert.Nil(t, cfg)
 	})
-	t.Run("WithInvalidNodeAddr", func(t *testing.T) {
-		cfg, err := NewConfig("Sys", "localhost")
-		require.Error(t, err)
-		assert.Nil(t, cfg)
-	})
 }
 
 func TestOptions(t *testing.T) {
@@ -72,8 +66,8 @@ func TestOptions(t *testing.T) {
 		},
 		{
 			name:           "WithRemoting",
-			option:         WithRemoting(),
-			expectedConfig: Config{remotingEnabled: true},
+			option:         WithRemoting("localhost", 3100),
+			expectedConfig: Config{remotingEnabled: true, remotingPort: 3100, remotingHost: "localhost"},
 		},
 	}
 	for _, tc := range testCases {
diff --git a/actors/local_address_test.go b/actors/local_address_test.go
deleted file mode 100644
index a95aac6..0000000
--- a/actors/local_address_test.go
+++ /dev/null
@@ -1,57 +0,0 @@
-package actors
-
-import (
-	"testing"
-
-	"github.com/stretchr/testify/assert"
-)
-
-func TestActorAddress(t *testing.T) {
-	t.Run("testCase1", func(t *testing.T) {
-		address := "goakt://sys@host:1234/abc/def/"
-		expected := "goakt://sys@host:1234"
-		addr := new(LocalAddress)
-		actual := addr.Parse(address)
-		assert.Equal(t, expected, actual.String())
-	})
-
-	t.Run("testCase2", func(t *testing.T) {
-		address := "goakt://sys/abc/def"
-		addr := new(LocalAddress)
-		assert.Panics(t, func() {
-			addr.Parse(address)
-		})
-	})
-
-	t.Run("testCase3", func(t *testing.T) {
-		address := "goakt://host:1234/abc/def/"
-		expected := "goakt://host:1234"
-		addr := new(LocalAddress)
-		actual := addr.Parse(address)
-		assert.Equal(t, expected, actual.String())
-	})
-
-	t.Run("testCase4", func(t *testing.T) {
-		address := "goakt://sys@host:1234"
-		expected := "goakt://sys@host:1234"
-		addr := new(LocalAddress)
-		actual := addr.Parse(address)
-		assert.Equal(t, expected, actual.String())
-	})
-
-	t.Run("testCase5", func(t *testing.T) {
-		address := "goakt://sys@host:1234/"
-		expected := "goakt://sys@host:1234"
-		addr := new(LocalAddress)
-		actual := addr.Parse(address)
-		assert.Equal(t, expected, actual.String())
-	})
-
-	t.Run("testCase6", func(t *testing.T) {
-		address := "goakt://sys@host/abc/def/"
-		addr := new(LocalAddress)
-		assert.Panics(t, func() {
-			addr.Parse(address)
-		})
-	})
-}
diff --git a/actors/path_test.go b/actors/path_test.go
index a1589ee..6ffa252 100644
--- a/actors/path_test.go
+++ b/actors/path_test.go
@@ -3,7 +3,6 @@ package actors
 import (
 	"testing"
 
-	comp "github.com/google/go-cmp/cmp"
 	"github.com/stretchr/testify/assert"
 	pb "github.com/tochemey/goakt/messages/v1"
 	"google.golang.org/protobuf/encoding/prototext"
@@ -11,7 +10,7 @@ import (
 
 func TestPath(t *testing.T) {
 	name := "TestActor"
-	addr := &LocalAddress{
+	addr := &Address{
 		host:     "localhost",
 		port:     888,
 		system:   "Sys",
@@ -23,7 +22,7 @@ func TestPath(t *testing.T) {
 	assert.IsType(t, new(Path), path)
 
 	// these are just routine assertions
-	assert.True(t, comp.Equal(addr, path.LocalAddress(), comp.AllowUnexported(LocalAddress{})))
+	assert.Nil(t, path.LocalAddress())
 	assert.Equal(t, name, path.Name())
 	assert.Equal(t, "goakt://Sys@localhost:888/TestActor", path.String())
 	remoteAddr := &pb.Address{
@@ -34,8 +33,8 @@ func TestPath(t *testing.T) {
 	}
 
 	pathRemoteAddr := &pb.Address{
-		Host: path.LocalAddress().Host(),
-		Port: int32(path.LocalAddress().Port()),
+		Host: path.Address().Host(),
+		Port: int32(path.Address().Port()),
 		Name: path.Name(),
 		Id:   path.ID().String(),
 	}
diff --git a/actors/pid_map_test.go b/actors/pid_map_test.go
index b419acb..ac98056 100644
--- a/actors/pid_map_test.go
+++ b/actors/pid_map_test.go
@@ -8,7 +8,7 @@ import (
 
 func TestPIDMap(t *testing.T) {
 	// create the actor path
-	actorPath := NewPath("Test", NewLocalAddress(protocol, "TestSys", "host", 444))
+	actorPath := NewPath("Test", NewAddress(protocol, "TestSys", "host", 444))
 	// create the PID
 	actorRef := &pid{actorPath: actorPath}
 	// create a new PID map
diff --git a/actors/pid_test.go b/actors/pid_test.go
index bedd0f5..9a88ef8 100644
--- a/actors/pid_test.go
+++ b/actors/pid_test.go
@@ -26,7 +26,7 @@ func TestActorReceive(t *testing.T) {
 	ctx := context.TODO()
 
 	// create the actor path
-	actorPath := NewPath("Test", NewLocalAddress(protocol, "sys", "host", 1))
+	actorPath := NewPath("Test", NewAddress(protocol, "sys", "host", 1))
 
 	// create the actor ref
 	pid := newPID(
@@ -68,7 +68,7 @@ func TestActorWithPassivation(t *testing.T) {
 	}
 
 	// create the actor path
-	actorPath := NewPath("Test", NewLocalAddress(protocol, "sys", "host", 1))
+	actorPath := NewPath("Test", NewAddress(protocol, "sys", "host", 1))
 	pid := newPID(ctx, actorPath, NewTestActor(), opts...)
 	assert.NotNil(t, pid)
 
@@ -97,7 +97,7 @@ func TestActorWithReply(t *testing.T) {
 		}
 
 		// create the actor path
-		actorPath := NewPath("Test", NewLocalAddress(protocol, "sys", "host", 1))
+		actorPath := NewPath("Test", NewAddress(protocol, "sys", "host", 1))
 		pid := newPID(ctx, actorPath, NewTestActor(), opts...)
 		assert.NotNil(t, pid)
 
@@ -120,7 +120,7 @@ func TestActorWithReply(t *testing.T) {
 		}
 
 		// create the actor path
-		actorPath := NewPath("Test", NewLocalAddress(protocol, "sys", "host", 1))
+		actorPath := NewPath("Test", NewAddress(protocol, "sys", "host", 1))
 		pid := newPID(ctx, actorPath, NewTestActor(), opts...)
 		assert.NotNil(t, pid)
 
@@ -137,7 +137,7 @@ func TestActorRestart(t *testing.T) {
 	t.Run("restart a stopped actor", func(t *testing.T) {
 		defer goleak.VerifyNone(t, goleak.IgnoreTopFunction("github.com/golang/glog.(*loggingT).flushDaemon"))
 		ctx := context.TODO()
-		cfg, err := NewConfig("testSys", "localhost:0")
+		cfg, err := NewConfig("testSys")
 		require.NoError(t, err)
 		assert.NotNil(t, cfg)
 
@@ -146,7 +146,7 @@ func TestActorRestart(t *testing.T) {
 		assert.NotNil(t, actor)
 
 		// create the actor path
-		actorPath := NewPath("Test", NewLocalAddress(protocol, "sys", "host", 1))
+		actorPath := NewPath("Test", NewAddress(protocol, "sys", "host", 1))
 		// create the actor ref
 		pid := newPID(ctx, actorPath, actor,
 			withInitMaxRetries(1),
@@ -185,7 +185,7 @@ func TestActorRestart(t *testing.T) {
 	//	defer goleak.VerifyNone(t)
 	//	ctx := context.TODO()
 	//	// create the actor path
-	//	actorPath := NewPath("Test", NewLocalAddress(protocol, "sys", "host", 1))
+	//	actorPath := NewPath("Test", NewAddress(protocol, "sys", "host", 1))
 	//
 	//	// create a Ping actor
 	//	pid := newPID(
@@ -213,7 +213,7 @@ func TestActorRestart(t *testing.T) {
 		actor := NewTestActor()
 		assert.NotNil(t, actor)
 		// create the actor path
-		actorPath := NewPath("Test", NewLocalAddress(protocol, "sys", "host", 1))
+		actorPath := NewPath("Test", NewAddress(protocol, "sys", "host", 1))
 
 		// create the actor ref
 		pid := newPID(ctx, actorPath, actor,
@@ -253,7 +253,7 @@ func TestChildActor(t *testing.T) {
 		// create a test context
 		ctx := context.TODO()
 		// create the actor path
-		actorPath := NewPath("Parent", NewLocalAddress(protocol, "sys", "host", 1))
+		actorPath := NewPath("Parent", NewAddress(protocol, "sys", "host", 1))
 
 		// create the parent actor
 		parent := newPID(ctx, actorPath,
@@ -287,7 +287,7 @@ func TestChildActor(t *testing.T) {
 		// create a test context
 		ctx := context.TODO()
 		// create the actor path
-		actorPath := NewPath("Parent", NewLocalAddress(protocol, "sys", "host", 1))
+		actorPath := NewPath("Parent", NewAddress(protocol, "sys", "host", 1))
 
 		// create the parent actor
 		parent := newPID(ctx,
@@ -327,7 +327,7 @@ func TestChildActor(t *testing.T) {
 
 		logger := log.DiscardLogger
 		// create the actor path
-		actorPath := NewPath("Parent", NewLocalAddress(protocol, "sys", "host", 1))
+		actorPath := NewPath("Parent", NewAddress(protocol, "sys", "host", 1))
 		// create the parent actor
 		parent := newPID(ctx,
 			actorPath,
@@ -368,7 +368,7 @@ func BenchmarkActor(b *testing.B) {
 
 		// create the actor ref
 		// create the actor path
-		actorPath := NewPath("Test", NewLocalAddress(protocol, "sys", "host", 1))
+		actorPath := NewPath("Test", NewAddress(protocol, "sys", "host", 1))
 		pid := newPID(ctx, actorPath, actor,
 			withInitMaxRetries(1),
 			withCustomLogger(log.DiscardLogger),
@@ -390,7 +390,7 @@ func BenchmarkActor(b *testing.B) {
 
 		// create the actor ref
 		// create the actor path
-		actorPath := NewPath("Test", NewLocalAddress(protocol, "sys", "host", 1))
+		actorPath := NewPath("Test", NewAddress(protocol, "sys", "host", 1))
 		pid := newPID(ctx, actorPath, actor,
 			withInitMaxRetries(1),
 			withCustomLogger(log.DiscardLogger),
@@ -409,7 +409,7 @@ func BenchmarkActor(b *testing.B) {
 
 		// create the actor ref
 		// create the actor path
-		actorPath := NewPath("Test", NewLocalAddress(protocol, "sys", "host", 1))
+		actorPath := NewPath("Test", NewAddress(protocol, "sys", "host", 1))
 		pid := newPID(ctx, actorPath, actor,
 			withInitMaxRetries(1),
 			withCustomLogger(log.DiscardLogger),
@@ -436,7 +436,7 @@ func BenchmarkActor(b *testing.B) {
 
 		// create the actor ref
 		// create the actor path
-		actorPath := NewPath("Test", NewLocalAddress(protocol, "sys", "host", 1))
+		actorPath := NewPath("Test", NewAddress(protocol, "sys", "host", 1))
 		pid := newPID(ctx, actorPath, actor,
 			withInitMaxRetries(1),
 			withCustomLogger(log.DiscardLogger),
@@ -465,7 +465,7 @@ func BenchmarkActor(b *testing.B) {
 
 		// create the actor ref
 		// create the actor path
-		actorPath := NewPath("Test", NewLocalAddress(protocol, "sys", "host", 1))
+		actorPath := NewPath("Test", NewAddress(protocol, "sys", "host", 1))
 		pid := newPID(ctx, actorPath, actor,
 			withInitMaxRetries(1),
 			withCustomLogger(log.DiscardLogger),
@@ -487,7 +487,7 @@ func BenchmarkActor(b *testing.B) {
 		actor := &BenchActor{}
 
 		// create the actor path
-		actorPath := NewPath("Test", NewLocalAddress(protocol, "sys", "host", 1))
+		actorPath := NewPath("Test", NewAddress(protocol, "sys", "host", 1))
 		// create the actor ref
 		pid := newPID(ctx, actorPath, actor,
 			withInitMaxRetries(1),
@@ -506,7 +506,7 @@ func BenchmarkActor(b *testing.B) {
 		ctx := context.TODO()
 		actor := &BenchActor{}
 		// create the actor path
-		actorPath := NewPath("Test", NewLocalAddress(protocol, "sys", "host", 1))
+		actorPath := NewPath("Test", NewAddress(protocol, "sys", "host", 1))
 		// create the actor ref
 		pid := newPID(ctx, actorPath, actor,
 			withInitMaxRetries(1),
@@ -533,7 +533,7 @@ func BenchmarkActor(b *testing.B) {
 		ctx := context.TODO()
 		actor := &BenchActor{}
 		// create the actor path
-		actorPath := NewPath("Test", NewLocalAddress(protocol, "sys", "host", 1))
+		actorPath := NewPath("Test", NewAddress(protocol, "sys", "host", 1))
 		// create the actor ref
 		pid := newPID(ctx, actorPath, actor,
 			withInitMaxRetries(1),