github.com/asynkron/protoactor-go@v0.0.0-20240308120642-ef91a6abee75/actor/actor_context.go (about)

     1  package actor
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  	"log/slog"
     8  	"runtime/debug"
     9  	"sync/atomic"
    10  	"time"
    11  
    12  	"github.com/asynkron/protoactor-go/ctxext"
    13  	"github.com/asynkron/protoactor-go/metrics"
    14  	"github.com/emirpasic/gods/stacks/linkedliststack"
    15  	"go.opentelemetry.io/otel/attribute"
    16  	"go.opentelemetry.io/otel/metric"
    17  )
    18  
    19  const (
    20  	stateAlive int32 = iota
    21  	stateRestarting
    22  	stateStopping
    23  	stateStopped
    24  )
    25  
    26  type actorContextExtras struct {
    27  	children            PIDSet
    28  	receiveTimeoutTimer *time.Timer
    29  	rs                  *RestartStatistics
    30  	stash               *linkedliststack.Stack
    31  	watchers            PIDSet
    32  	context             Context
    33  	extensions          *ctxext.ContextExtensions
    34  }
    35  
    36  func newActorContextExtras(context Context) *actorContextExtras {
    37  	this := &actorContextExtras{
    38  		context:    context,
    39  		extensions: ctxext.NewContextExtensions(),
    40  	}
    41  
    42  	return this
    43  }
    44  
    45  func (ctxExt *actorContextExtras) restartStats() *RestartStatistics {
    46  	// lazy initialize the child restart stats if this is the first time
    47  	// further mutations are handled within "restart"
    48  	if ctxExt.rs == nil {
    49  		ctxExt.rs = NewRestartStatistics()
    50  	}
    51  
    52  	return ctxExt.rs
    53  }
    54  
    55  func (ctxExt *actorContextExtras) initReceiveTimeoutTimer(timer *time.Timer) {
    56  	ctxExt.receiveTimeoutTimer = timer
    57  }
    58  
    59  func (ctxExt *actorContextExtras) resetReceiveTimeoutTimer(time time.Duration) {
    60  	if ctxExt.receiveTimeoutTimer == nil {
    61  		return
    62  	}
    63  
    64  	ctxExt.receiveTimeoutTimer.Reset(time)
    65  }
    66  
    67  func (ctxExt *actorContextExtras) stopReceiveTimeoutTimer() {
    68  	if ctxExt.receiveTimeoutTimer == nil {
    69  		return
    70  	}
    71  
    72  	ctxExt.receiveTimeoutTimer.Stop()
    73  }
    74  
    75  func (ctxExt *actorContextExtras) killReceiveTimeoutTimer() {
    76  	if ctxExt.receiveTimeoutTimer == nil {
    77  		return
    78  	}
    79  
    80  	ctxExt.receiveTimeoutTimer.Stop()
    81  	ctxExt.receiveTimeoutTimer = nil
    82  }
    83  
    84  func (ctxExt *actorContextExtras) addChild(pid *PID) {
    85  	ctxExt.children.Add(pid)
    86  }
    87  
    88  func (ctxExt *actorContextExtras) removeChild(pid *PID) {
    89  	ctxExt.children.Remove(pid)
    90  }
    91  
    92  func (ctxExt *actorContextExtras) watch(watcher *PID) {
    93  	ctxExt.watchers.Add(watcher)
    94  }
    95  
    96  func (ctxExt *actorContextExtras) unwatch(watcher *PID) {
    97  	ctxExt.watchers.Remove(watcher)
    98  }
    99  
   100  type actorContext struct {
   101  	actor             Actor
   102  	actorSystem       *ActorSystem
   103  	extras            *actorContextExtras
   104  	props             *Props
   105  	parent            *PID
   106  	self              *PID
   107  	receiveTimeout    time.Duration
   108  	messageOrEnvelope interface{}
   109  	state             int32
   110  }
   111  
   112  var (
   113  	_ SenderContext   = &actorContext{}
   114  	_ ReceiverContext = &actorContext{}
   115  	_ SpawnerContext  = &actorContext{}
   116  	_ basePart        = &actorContext{}
   117  	_ stopperPart     = &actorContext{}
   118  )
   119  
   120  func newActorContext(actorSystem *ActorSystem, props *Props, parent *PID) *actorContext {
   121  	this := &actorContext{
   122  		parent:      parent,
   123  		props:       props,
   124  		actorSystem: actorSystem,
   125  	}
   126  
   127  	this.incarnateActor()
   128  
   129  	return this
   130  }
   131  
   132  func (ctx *actorContext) ensureExtras() *actorContextExtras {
   133  	if ctx.extras == nil {
   134  		ctxd := Context(ctx)
   135  		if ctx.props != nil && ctx.props.contextDecoratorChain != nil {
   136  			ctxd = ctx.props.contextDecoratorChain(ctxd)
   137  		}
   138  
   139  		ctx.extras = newActorContextExtras(ctxd)
   140  	}
   141  
   142  	return ctx.extras
   143  }
   144  
   145  //
   146  // Interface: Context
   147  //
   148  
   149  func (ctx *actorContext) ActorSystem() *ActorSystem {
   150  	return ctx.actorSystem
   151  }
   152  
   153  func (ctx *actorContext) Logger() *slog.Logger {
   154  	return ctx.actorSystem.Logger()
   155  }
   156  
   157  func (ctx *actorContext) Parent() *PID {
   158  	return ctx.parent
   159  }
   160  
   161  func (ctx *actorContext) Self() *PID {
   162  	return ctx.self
   163  }
   164  
   165  func (ctx *actorContext) Sender() *PID {
   166  	return UnwrapEnvelopeSender(ctx.messageOrEnvelope)
   167  }
   168  
   169  func (ctx *actorContext) Actor() Actor {
   170  	return ctx.actor
   171  }
   172  
   173  func (ctx *actorContext) ReceiveTimeout() time.Duration {
   174  	return ctx.receiveTimeout
   175  }
   176  
   177  func (ctx *actorContext) Children() []*PID {
   178  	if ctx.extras == nil {
   179  		return make([]*PID, 0)
   180  	}
   181  
   182  	return ctx.extras.children.Values()
   183  }
   184  
   185  func (ctx *actorContext) Respond(response interface{}) {
   186  	// If the message is addressed to nil forward it to the dead letter channel
   187  	if ctx.Sender() == nil {
   188  		ctx.actorSystem.DeadLetter.SendUserMessage(nil, response)
   189  
   190  		return
   191  	}
   192  
   193  	ctx.Send(ctx.Sender(), response)
   194  }
   195  
   196  func (ctx *actorContext) Stash() {
   197  	extra := ctx.ensureExtras()
   198  	if extra.stash == nil {
   199  		extra.stash = linkedliststack.New()
   200  	}
   201  
   202  	extra.stash.Push(ctx.Message())
   203  }
   204  
   205  func (ctx *actorContext) Watch(who *PID) {
   206  	who.sendSystemMessage(ctx.actorSystem, &Watch{
   207  		Watcher: ctx.self,
   208  	})
   209  }
   210  
   211  func (ctx *actorContext) Unwatch(who *PID) {
   212  	who.sendSystemMessage(ctx.actorSystem, &Unwatch{
   213  		Watcher: ctx.self,
   214  	})
   215  }
   216  
   217  func (ctx *actorContext) SetReceiveTimeout(d time.Duration) {
   218  	if d < time.Millisecond {
   219  		// anything less than 1 millisecond is set to zero
   220  		d = 0
   221  	}
   222  
   223  	if d == ctx.receiveTimeout {
   224  		return
   225  	}
   226  
   227  	ctx.receiveTimeout = d
   228  
   229  	ctx.ensureExtras()
   230  	ctx.extras.stopReceiveTimeoutTimer()
   231  
   232  	if d > 0 {
   233  		if ctx.extras.receiveTimeoutTimer == nil {
   234  			ctx.extras.initReceiveTimeoutTimer(time.AfterFunc(d, ctx.receiveTimeoutHandler))
   235  		} else {
   236  			ctx.extras.resetReceiveTimeoutTimer(d)
   237  		}
   238  	}
   239  }
   240  
   241  func (ctx *actorContext) CancelReceiveTimeout() {
   242  	if ctx.extras == nil || ctx.extras.receiveTimeoutTimer == nil {
   243  		return
   244  	}
   245  
   246  	ctx.extras.killReceiveTimeoutTimer()
   247  	ctx.receiveTimeout = 0
   248  }
   249  
   250  func (ctx *actorContext) receiveTimeoutHandler() {
   251  	if ctx.extras != nil && ctx.extras.receiveTimeoutTimer != nil {
   252  		ctx.CancelReceiveTimeout()
   253  		ctx.Send(ctx.self, receiveTimeoutMessage)
   254  	}
   255  }
   256  
   257  func (ctx *actorContext) Forward(pid *PID) {
   258  	if msg, ok := ctx.messageOrEnvelope.(SystemMessage); ok {
   259  		// SystemMessage cannot be forwarded
   260  		ctx.Logger().Error("SystemMessage cannot be forwarded", slog.Any("message", msg))
   261  
   262  		return
   263  	}
   264  
   265  	ctx.sendUserMessage(pid, ctx.messageOrEnvelope)
   266  }
   267  
   268  func (ctx *actorContext) ReenterAfter(f *Future, cont func(res interface{}, err error)) {
   269  	wrapper := func() {
   270  		cont(f.result, f.err)
   271  	}
   272  
   273  	message := ctx.messageOrEnvelope
   274  	// invoke the callback when the future completes
   275  	f.continueWith(func(res interface{}, err error) {
   276  		// send the wrapped callback as a continuation message to self
   277  		ctx.self.sendSystemMessage(ctx.actorSystem, &continuation{
   278  			f:       wrapper,
   279  			message: message,
   280  		})
   281  	})
   282  }
   283  
   284  //
   285  // Interface: sender
   286  //
   287  
   288  func (ctx *actorContext) Message() interface{} {
   289  	return UnwrapEnvelopeMessage(ctx.messageOrEnvelope)
   290  }
   291  
   292  func (ctx *actorContext) MessageHeader() ReadonlyMessageHeader {
   293  	return UnwrapEnvelopeHeader(ctx.messageOrEnvelope)
   294  }
   295  
   296  func (ctx *actorContext) Send(pid *PID, message interface{}) {
   297  	ctx.sendUserMessage(pid, message)
   298  }
   299  
   300  func (ctx *actorContext) sendUserMessage(pid *PID, message interface{}) {
   301  	if ctx.props.senderMiddlewareChain != nil {
   302  		ctx.props.senderMiddlewareChain(ctx.ensureExtras().context, pid, WrapEnvelope(message))
   303  	} else {
   304  		pid.sendUserMessage(ctx.actorSystem, message)
   305  	}
   306  }
   307  
   308  func (ctx *actorContext) Request(pid *PID, message interface{}) {
   309  	env := &MessageEnvelope{
   310  		Header:  nil,
   311  		Message: message,
   312  		Sender:  ctx.Self(),
   313  	}
   314  
   315  	ctx.sendUserMessage(pid, env)
   316  }
   317  
   318  func (ctx *actorContext) RequestWithCustomSender(pid *PID, message interface{}, sender *PID) {
   319  	env := &MessageEnvelope{
   320  		Header:  nil,
   321  		Message: message,
   322  		Sender:  sender,
   323  	}
   324  	ctx.sendUserMessage(pid, env)
   325  }
   326  
   327  func (ctx *actorContext) RequestFuture(pid *PID, message interface{}, timeout time.Duration) *Future {
   328  	future := NewFuture(ctx.actorSystem, timeout)
   329  	env := &MessageEnvelope{
   330  		Header:  nil,
   331  		Message: message,
   332  		Sender:  future.PID(),
   333  	}
   334  	ctx.sendUserMessage(pid, env)
   335  
   336  	return future
   337  }
   338  
   339  //
   340  // Interface: receiver
   341  //
   342  
   343  func (ctx *actorContext) Receive(envelope *MessageEnvelope) {
   344  	ctx.messageOrEnvelope = envelope
   345  	ctx.defaultReceive()
   346  	ctx.messageOrEnvelope = nil
   347  }
   348  
   349  func (ctx *actorContext) defaultReceive() {
   350  	switch msg := ctx.Message().(type) {
   351  	case *PoisonPill:
   352  		ctx.Stop(ctx.self)
   353  
   354  	case AutoRespond:
   355  		if ctx.props.contextDecoratorChain != nil {
   356  			ctx.actor.Receive(ctx.ensureExtras().context)
   357  		} else {
   358  			ctx.actor.Receive(ctx)
   359  		}
   360  
   361  		res := msg.GetAutoResponse(ctx)
   362  		ctx.Respond(res)
   363  
   364  	default:
   365  		// are we using decorators, if so, ensure it has been created
   366  		if ctx.props.contextDecoratorChain != nil {
   367  			ctx.actor.Receive(ctx.ensureExtras().context)
   368  
   369  			return
   370  		}
   371  
   372  		ctx.actor.Receive(ctx)
   373  	}
   374  }
   375  
   376  //
   377  // Interface: spawner
   378  //
   379  
   380  func (ctx *actorContext) Spawn(props *Props) *PID {
   381  	pid, err := ctx.SpawnNamed(props, ctx.actorSystem.ProcessRegistry.NextId())
   382  	if err != nil {
   383  		panic(err)
   384  	}
   385  
   386  	return pid
   387  }
   388  
   389  func (ctx *actorContext) SpawnPrefix(props *Props, prefix string) *PID {
   390  	pid, err := ctx.SpawnNamed(props, prefix+ctx.actorSystem.ProcessRegistry.NextId())
   391  	if err != nil {
   392  		panic(err)
   393  	}
   394  
   395  	return pid
   396  }
   397  
   398  func (ctx *actorContext) SpawnNamed(props *Props, name string) (*PID, error) {
   399  	if props.guardianStrategy != nil {
   400  		panic(errors.New("props used to spawn child cannot have GuardianStrategy"))
   401  	}
   402  
   403  	var pid *PID
   404  
   405  	var err error
   406  
   407  	if ctx.props.spawnMiddlewareChain != nil {
   408  		pid, err = ctx.props.spawnMiddlewareChain(ctx.actorSystem, ctx.self.Id+"/"+name, props, ctx)
   409  	} else {
   410  		pid, err = props.spawn(ctx.actorSystem, ctx.self.Id+"/"+name, ctx)
   411  	}
   412  
   413  	if err != nil {
   414  		return pid, err
   415  	}
   416  
   417  	ctx.ensureExtras().addChild(pid)
   418  
   419  	return pid, nil
   420  }
   421  
   422  //
   423  // Interface: stopper
   424  //
   425  
   426  // Stop will stop actor immediately regardless of existing user messages in mailbox.
   427  func (ctx *actorContext) Stop(pid *PID) {
   428  	if ctx.actorSystem.Config.MetricsProvider != nil {
   429  		metricsSystem, ok := ctx.actorSystem.Extensions.Get(extensionId).(*Metrics)
   430  		if ok && metricsSystem.enabled {
   431  			_ctx := context.Background()
   432  			if instruments := metricsSystem.metrics.Get(metrics.InternalActorMetrics); instruments != nil {
   433  				instruments.ActorStoppedCount.Add(_ctx, 1, metric.WithAttributes(metricsSystem.CommonLabels(ctx)...))
   434  			}
   435  		}
   436  	}
   437  
   438  	pid.ref(ctx.actorSystem).Stop(pid)
   439  }
   440  
   441  // StopFuture will stop actor immediately regardless of existing user messages in mailbox, and return its future.
   442  func (ctx *actorContext) StopFuture(pid *PID) *Future {
   443  	future := NewFuture(ctx.actorSystem, 10*time.Second)
   444  
   445  	pid.sendSystemMessage(ctx.actorSystem, &Watch{Watcher: future.pid})
   446  	ctx.Stop(pid)
   447  
   448  	return future
   449  }
   450  
   451  // Poison will tell actor to stop after processing current user messages in mailbox.
   452  func (ctx *actorContext) Poison(pid *PID) {
   453  	pid.sendUserMessage(ctx.actorSystem, poisonPillMessage)
   454  }
   455  
   456  // PoisonFuture will tell actor to stop after processing current user messages in mailbox, and return its future.
   457  func (ctx *actorContext) PoisonFuture(pid *PID) *Future {
   458  	future := NewFuture(ctx.actorSystem, 10*time.Second)
   459  
   460  	pid.sendSystemMessage(ctx.actorSystem, &Watch{Watcher: future.pid})
   461  	ctx.Poison(pid)
   462  
   463  	return future
   464  }
   465  
   466  //
   467  // Interface: MessageInvoker
   468  //
   469  
   470  func (ctx *actorContext) InvokeUserMessage(md interface{}) {
   471  	if atomic.LoadInt32(&ctx.state) == stateStopped {
   472  		// already stopped
   473  		return
   474  	}
   475  
   476  	influenceTimeout := true
   477  	if ctx.receiveTimeout > 0 {
   478  		_, influenceTimeout = md.(NotInfluenceReceiveTimeout)
   479  		influenceTimeout = !influenceTimeout
   480  
   481  		if influenceTimeout {
   482  			ctx.extras.stopReceiveTimeoutTimer()
   483  		}
   484  	}
   485  
   486  	systemMetrics, ok := ctx.actorSystem.Extensions.Get(extensionId).(*Metrics)
   487  	if ok && systemMetrics.enabled {
   488  		t := time.Now()
   489  
   490  		ctx.processMessage(md)
   491  
   492  		delta := time.Since(t)
   493  		_ctx := context.Background()
   494  
   495  		if instruments := systemMetrics.metrics.Get(metrics.InternalActorMetrics); instruments != nil {
   496  			histogram := instruments.ActorMessageReceiveHistogram
   497  
   498  			labels := append(
   499  				systemMetrics.CommonLabels(ctx),
   500  				attribute.String("messagetype", fmt.Sprintf("%T", md)),
   501  			)
   502  			histogram.Record(_ctx, delta.Seconds(), metric.WithAttributes(labels...))
   503  		}
   504  	} else {
   505  		ctx.processMessage(md)
   506  	}
   507  
   508  	if ctx.receiveTimeout > 0 && influenceTimeout {
   509  		ctx.extras.resetReceiveTimeoutTimer(ctx.receiveTimeout)
   510  	}
   511  }
   512  
   513  func (ctx *actorContext) processMessage(m interface{}) {
   514  	if ctx.props.receiverMiddlewareChain != nil {
   515  		ctx.props.receiverMiddlewareChain(ctx.ensureExtras().context, WrapEnvelope(m))
   516  
   517  		return
   518  	}
   519  
   520  	if ctx.props.contextDecoratorChain != nil {
   521  		ctx.ensureExtras().context.Receive(WrapEnvelope(m))
   522  
   523  		return
   524  	}
   525  
   526  	ctx.messageOrEnvelope = m
   527  	ctx.defaultReceive()
   528  	ctx.messageOrEnvelope = nil // release message
   529  }
   530  
   531  func (ctx *actorContext) incarnateActor() {
   532  	atomic.StoreInt32(&ctx.state, stateAlive)
   533  	ctx.actor = ctx.props.producer(ctx.actorSystem)
   534  
   535  	metricsSystem, ok := ctx.actorSystem.Extensions.Get(extensionId).(*Metrics)
   536  	if ok && metricsSystem.enabled {
   537  		_ctx := context.Background()
   538  		if instruments := metricsSystem.metrics.Get(metrics.InternalActorMetrics); instruments != nil {
   539  			instruments.ActorSpawnCount.Add(_ctx, 1, metric.WithAttributes(metricsSystem.CommonLabels(ctx)...))
   540  		}
   541  	}
   542  }
   543  
   544  func (ctx *actorContext) InvokeSystemMessage(message interface{}) {
   545  	//goland:noinspection GrazieInspection
   546  	switch msg := message.(type) {
   547  	case *continuation:
   548  		ctx.messageOrEnvelope = msg.message // apply the message that was present when we started the await
   549  		msg.f()                             // invoke the continuation in the current actor context
   550  
   551  		ctx.messageOrEnvelope = nil // release the message
   552  	case *Started:
   553  		ctx.InvokeUserMessage(msg) // forward
   554  	case *Watch:
   555  		ctx.handleWatch(msg)
   556  	case *Unwatch:
   557  		ctx.handleUnwatch(msg)
   558  	case *Stop:
   559  		ctx.handleStop()
   560  	case *Terminated:
   561  		ctx.handleTerminated(msg)
   562  	case *Failure:
   563  		ctx.handleFailure(msg)
   564  	case *Restart:
   565  		ctx.handleRestart()
   566  	default:
   567  		ctx.Logger().Error("unknown system message", slog.Any("message", msg))
   568  	}
   569  }
   570  
   571  func (ctx *actorContext) handleRootFailure(failure *Failure) {
   572  	defaultSupervisionStrategy.HandleFailure(ctx.actorSystem, ctx, failure.Who, failure.RestartStats, failure.Reason, failure.Message)
   573  }
   574  
   575  func (ctx *actorContext) handleWatch(msg *Watch) {
   576  	if atomic.LoadInt32(&ctx.state) >= stateStopping {
   577  		msg.Watcher.sendSystemMessage(ctx.actorSystem, &Terminated{
   578  			Who: ctx.self,
   579  		})
   580  	} else {
   581  		ctx.ensureExtras().watch(msg.Watcher)
   582  	}
   583  }
   584  
   585  func (ctx *actorContext) handleUnwatch(msg *Unwatch) {
   586  	if ctx.extras == nil {
   587  		return
   588  	}
   589  
   590  	ctx.extras.unwatch(msg.Watcher)
   591  }
   592  
   593  func (ctx *actorContext) handleRestart() {
   594  	atomic.StoreInt32(&ctx.state, stateRestarting)
   595  	ctx.InvokeUserMessage(restartingMessage)
   596  	ctx.stopAllChildren()
   597  	ctx.tryRestartOrTerminate()
   598  
   599  	metricsSystem, ok := ctx.actorSystem.Extensions.Get(extensionId).(*Metrics)
   600  	if ok && metricsSystem.enabled {
   601  		_ctx := context.Background()
   602  		if instruments := metricsSystem.metrics.Get(metrics.InternalActorMetrics); instruments != nil {
   603  			instruments.ActorRestartedCount.Add(_ctx, 1, metric.WithAttributes(metricsSystem.CommonLabels(ctx)...))
   604  		}
   605  	}
   606  }
   607  
   608  // I am stopping.
   609  func (ctx *actorContext) handleStop() {
   610  	if atomic.LoadInt32(&ctx.state) >= stateStopping {
   611  		// already stopping or stopped
   612  		return
   613  	}
   614  
   615  	atomic.StoreInt32(&ctx.state, stateStopping)
   616  
   617  	ctx.InvokeUserMessage(stoppingMessage)
   618  	ctx.stopAllChildren()
   619  	ctx.tryRestartOrTerminate()
   620  }
   621  
   622  // child stopped, check if we can stop or restart (if needed).
   623  func (ctx *actorContext) handleTerminated(msg *Terminated) {
   624  	if ctx.extras != nil {
   625  		ctx.extras.removeChild(msg.Who)
   626  	}
   627  
   628  	ctx.InvokeUserMessage(msg)
   629  	ctx.tryRestartOrTerminate()
   630  }
   631  
   632  // offload the supervision completely to the supervisor strategy.
   633  func (ctx *actorContext) handleFailure(msg *Failure) {
   634  	if strategy, ok := ctx.actor.(SupervisorStrategy); ok {
   635  		strategy.HandleFailure(ctx.actorSystem, ctx, msg.Who, msg.RestartStats, msg.Reason, msg.Message)
   636  
   637  		return
   638  	}
   639  
   640  	ctx.props.getSupervisor().HandleFailure(ctx.actorSystem, ctx, msg.Who, msg.RestartStats, msg.Reason, msg.Message)
   641  }
   642  
   643  func (ctx *actorContext) stopAllChildren() {
   644  	if ctx.extras == nil {
   645  		return
   646  	}
   647  
   648  	pids := ctx.extras.children.pids
   649  	for i := len(pids) - 1; i >= 0; i-- {
   650  		pids[i].sendSystemMessage(ctx.actorSystem, stopMessage)
   651  	}
   652  }
   653  
   654  func (ctx *actorContext) tryRestartOrTerminate() {
   655  	if ctx.extras != nil && !ctx.extras.children.Empty() {
   656  		return
   657  	}
   658  
   659  	switch atomic.LoadInt32(&ctx.state) {
   660  	case stateRestarting:
   661  		ctx.CancelReceiveTimeout()
   662  		ctx.restart()
   663  	case stateStopping:
   664  		ctx.CancelReceiveTimeout()
   665  		ctx.finalizeStop()
   666  	}
   667  }
   668  
   669  func (ctx *actorContext) restart() {
   670  	ctx.incarnateActor()
   671  	ctx.self.sendSystemMessage(ctx.actorSystem, resumeMailboxMessage)
   672  	ctx.InvokeUserMessage(startedMessage)
   673  
   674  	if ctx.extras != nil && ctx.extras.stash != nil {
   675  		for !ctx.extras.stash.Empty() {
   676  			msg, _ := ctx.extras.stash.Pop()
   677  			ctx.InvokeUserMessage(msg)
   678  		}
   679  	}
   680  }
   681  
   682  func (ctx *actorContext) finalizeStop() {
   683  	ctx.actorSystem.ProcessRegistry.Remove(ctx.self)
   684  	ctx.InvokeUserMessage(stoppedMessage)
   685  
   686  	otherStopped := &Terminated{Who: ctx.self}
   687  	// Notify watchers
   688  	if ctx.extras != nil {
   689  		ctx.extras.watchers.ForEach(func(i int, pid *PID) {
   690  			pid.sendSystemMessage(ctx.actorSystem, otherStopped)
   691  		})
   692  	}
   693  	// Notify parent
   694  	if ctx.parent != nil {
   695  		ctx.parent.sendSystemMessage(ctx.actorSystem, otherStopped)
   696  	}
   697  
   698  	atomic.StoreInt32(&ctx.state, stateStopped)
   699  }
   700  
   701  //
   702  // Interface: Supervisor
   703  //
   704  
   705  func (ctx *actorContext) EscalateFailure(reason interface{}, message interface{}) {
   706  	ctx.Logger().Info("[ACTOR] Recovering", slog.Any("self", ctx.self), slog.Any("reason", reason))
   707  	// debug setting, allows to output supervision failures in console/error level
   708  	if ctx.actorSystem.Config.DeveloperSupervisionLogging {
   709  		fmt.Printf("debug.Stack(): %s\n", debug.Stack())
   710  		fmt.Println("[Supervision] Actor:", ctx.self, " failed with message:", message, " exception:", reason)
   711  		ctx.Logger().Error("[Supervision]", slog.Any("actor", ctx.self), slog.Any("message", message), slog.Any("exception", reason))
   712  	}
   713  
   714  	metricsSystem, ok := ctx.actorSystem.Extensions.Get(extensionId).(*Metrics)
   715  	if ok && metricsSystem.enabled {
   716  		_ctx := context.Background()
   717  		if instruments := metricsSystem.metrics.Get(metrics.InternalActorMetrics); instruments != nil {
   718  			instruments.ActorFailureCount.Add(_ctx, 1, metric.WithAttributes(metricsSystem.CommonLabels(ctx)...))
   719  		}
   720  	}
   721  
   722  	failure := &Failure{Reason: reason, Who: ctx.self, RestartStats: ctx.ensureExtras().restartStats(), Message: message}
   723  
   724  	ctx.self.sendSystemMessage(ctx.actorSystem, suspendMailboxMessage)
   725  
   726  	if ctx.parent == nil {
   727  		ctx.handleRootFailure(failure)
   728  	} else {
   729  		ctx.parent.sendSystemMessage(ctx.actorSystem, failure)
   730  	}
   731  }
   732  
   733  func (ctx *actorContext) RestartChildren(pids ...*PID) {
   734  	for _, pid := range pids {
   735  		pid.sendSystemMessage(ctx.actorSystem, restartMessage)
   736  	}
   737  }
   738  
   739  func (ctx *actorContext) StopChildren(pids ...*PID) {
   740  	for _, pid := range pids {
   741  		pid.sendSystemMessage(ctx.actorSystem, stopMessage)
   742  	}
   743  }
   744  
   745  func (ctx *actorContext) ResumeChildren(pids ...*PID) {
   746  	for _, pid := range pids {
   747  		pid.sendSystemMessage(ctx.actorSystem, resumeMailboxMessage)
   748  	}
   749  }
   750  
   751  //
   752  // Miscellaneous
   753  //
   754  
   755  func (ctx *actorContext) GoString() string {
   756  	return ctx.self.String()
   757  }
   758  
   759  func (ctx *actorContext) String() string {
   760  	return ctx.self.String()
   761  }
   762  
   763  func (ctx *actorContext) Get(id ctxext.ContextExtensionID) ctxext.ContextExtension {
   764  	extras := ctx.ensureExtras()
   765  	ext := extras.extensions.Get(id)
   766  
   767  	return ext
   768  }
   769  
   770  func (ctx *actorContext) Set(ext ctxext.ContextExtension) {
   771  	extras := ctx.ensureExtras()
   772  	extras.extensions.Set(ext)
   773  }