bug: Cannot fetch dead actor for respawning #887
-
|
Bug description How to reproduce it? exists, err := r.self.ActorSystem().ActorExists(ctx, id) //exists and err are true and nil
if err == nil {
if exists {
_, pid, err := r.self.ActorSystem().ActorOf(ctx, id) //pid and err are both nil
if err != nil {
fmt.Printf("Failed to fetch respawnable actor: %v\n", err)
return &Error{Message: "Unable"}
} else {
if !pid.IsRunning() { //fails because pid is nil
pid.Reinstate(pid)
}
}
}
} else {
fmt.Printf("Failed to lookup actor: %v\n", err) //never printed
return &Error{Message: "Unable"}
}
err = r.self.ActorSystem().SpawnOn(ctx, id, NewRule(), goakt.WithLongLived())
if err != nil {
fmt.Printf("Failed to create actor: %v", err)
return &Error{Message: "Unable"}
}
return &Error{Message: "Done"}Expected behavior Screenshots Library Version:
Additional context |
Beta Was this translation helpful? Give feedback.
Replies: 10 comments 11 replies
-
|
@CristianoBarone when an actor stop existing, it is completely wiped out from the system and there is no way to respawn them except creating a new instance. That is the lifecycle of an actor. It is only Grains that can get reactivated on message. I would like to clarify that first before looking into your issue. |
Beta Was this translation helpful? Give feedback.
-
Therefore if the actor exist you just send it message using I am of the opinion this is an issue related to how you are using the library. |
Beta Was this translation helpful? Give feedback.
-
Then the problem is that when the actor is stopped it isn't wiped from the system, so it cannot be spawned again. I will send you the code that takes care of stopping the actors tomorrow. |
Beta Was this translation helpful? Give feedback.
-
|
@CristianoBarone Dead actor do not exist in the system. I have provided a sample code here for you to peruse and run it locally: package main
import (
"context"
"errors"
"fmt"
"os"
"time"
"github.com/tochemey/goakt/v3/actor"
gerrors "github.com/tochemey/goakt/v3/errors"
"github.com/tochemey/goakt/v3/goaktpb"
"github.com/tochemey/goakt/v3/log"
)
func main() {
ctx := context.Background()
logger := log.DiscardLogger
fmt.Println("Starting actor system...")
actorSystem, _ := actor.NewActorSystem("Test", actor.WithLogger(logger))
if err := actorSystem.Start(ctx); err != nil {
fmt.Printf("failed to start actor system: %v\n", err)
os.Exit(1)
}
fmt.Println("\nSpawning actor...")
pid, err := actorSystem.Spawn(ctx, "actor1", &MyActor{}, actor.WithLongLived())
if err != nil {
fmt.Printf("failed to spawn actor: %v\n", err)
os.Exit(1)
}
fmt.Println("\nStopping actor...")
if err := pid.Shutdown(ctx); err != nil {
fmt.Printf("failed to stop actor: %v\n", err)
os.Exit(1)
}
// wait for a while to ensure the actor is stopped
time.Sleep(time.Second)
ok, err := actorSystem.ActorExists(ctx, "actor1")
if err != nil {
fmt.Println("failed to check if actor exists:", err)
os.Exit(1)
}
if ok {
fmt.Println("actor should be stopped but still exists")
os.Exit(1)
}
addr, pid, err := actorSystem.ActorOf(ctx, "actor1")
if err != nil {
if !errors.Is(err, gerrors.ErrActorNotFound) {
fmt.Println("failed to get actor:", err)
os.Exit(1)
}
}
if addr != nil || pid != nil {
fmt.Println("actor should be stopped but still exists")
os.Exit(1)
}
fmt.Println("Actor stopped successfully")
fmt.Println("\nStopping actor system...")
_ = actorSystem.Stop(ctx)
}
type MyActor struct{}
var _ actor.Actor = (*MyActor)(nil)
func (x *MyActor) PreStart(*actor.Context) error {
fmt.Println("PreStart")
return nil
}
func (x *MyActor) Receive(ctx *actor.ReceiveContext) {
switch ctx.Message().(type) {
case *goaktpb.PostStart:
fmt.Println("PostStart")
default:
ctx.Unhandled()
}
}
func (x *MyActor) PostStop(*actor.Context) error {
fmt.Println("PostStop")
return nil
} |
Beta Was this translation helpful? Give feedback.
-
|
@CristianoBarone can you please elaborate on this:
|
Beta Was this translation helpful? Give feedback.
-
|
I have a system in which an actor with multiple children is spawned, at a point the actor must be terminated. If for any reason one of the children is not alive, the actor will throw that error and fail to terminate, however it will terminate at the second try. When at a latter moment in time the actor is to be respawned, it won't, stating the actor already exists. |
Beta Was this translation helpful? Give feedback.
-
|
That isn’t a GoAkt bug — it’s related to your application’s design. Unfortunately, I can’t provide much direct help with that. You may need to revisit your design with respect to the actor model paradigm. I hope you read this part of the doc:https://tochemey.gitbook.io/goakt/features/supervision. |
Beta Was this translation helpful? Give feedback.
-
|
@CristianoBarone let us continue the conversation here. If it is a real issue then I can move it back to issues. Thanks |
Beta Was this translation helpful? Give feedback.
-
|
@CristianoBarone would you mind sharing your experience with GoAkt if you guys are using it in production? |
Beta Was this translation helpful? Give feedback.
-
|
@CristianoBarone I released a new tag that should get some of your concerns addressed except for the logging :) https://github.com/Tochemey/goakt/releases/tag/v3.9.2 |
Beta Was this translation helpful? Give feedback.
@CristianoBarone I released a new tag that should get some of your concerns addressed except for the logging :) https://github.com/Tochemey/goakt/releases/tag/v3.9.2