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 }