Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How can I make ‘Spawn’ return the error that occurred when 'Started' is received? #1105

Open
DustOak opened this issue Apr 19, 2024 · 4 comments

Comments

@DustOak
Copy link

DustOak commented Apr 19, 2024

When I spawn an actor, if I need to initialize the actor upon receiving 'Started', and if initialization fails, the actor should not start successfully. How should I write this code? I noticed that after I receive 'Started', the spawn has already returned the Pid. However, I do not want this because I need the actor to stop when initialization fails and have the spawn return an error

@rogeralsing
Copy link
Collaborator

I would rather wrap all that in a helper function that handles all of this.
e.g. if your code fails to initialize, set some state of the actor to failed.
then add a message request+response where you can query that state.

func NewSomeActor() {
       	props := actor.PropsFromProducer(......)
        pid := system.Root.Spawn(props)
        res := system.Root.RequestFuture(pid, &SomeRequest {}).Result
        if res == .... {
                 //actor started successfully
        }
        else {
                  //actor failed to initialize
        }
}

Or if possible, you could do it even before proto.actor is involved at all.
You can set state in the actor upon producing it.

func() actor.Actor { return &helloActor{
     .....set state here
} }

you could create a function that resolves all deps and returns a Props if successful, or err if failed.
That way, you could catch this error before the actor is spawned.

@DustOak
Copy link
Author

DustOak commented Apr 22, 2024

我宁愿将所有这些包装在一个处理所有这些的帮助程序函数中。例如,如果您的代码无法初始化,请将 actor 的某些状态设置为 failed。然后添加消息 request+response,您可以在其中查询该状态。

func NewSomeActor() {
       	props := actor.PropsFromProducer(......)
        pid := system.Root.Spawn(props)
        res := system.Root.RequestFuture(pid, &SomeRequest {}).Result
        if res == .... {
                 //actor started successfully
        }
        else {
                  //actor failed to initialize
        }
}

或者,如果可能的话,你甚至可以在 proto.actor 参与之前就这样做。您可以在生成 actor 时在 actor 中设置状态。

func() actor.Actor { return &helloActor{
     .....set state here
} }

您可以创建一个函数来解析所有 deps,如果成功,则返回 Props,如果失败,则返回 err。这样,您就可以在生成 actor 之前捕获此错误。

I have considered and tried the first method, but I am unable to determine how long the timeout for synchronous requests should be set. If the time is too long, it may affect the overall performance.

@DustOak
Copy link
Author

DustOak commented Apr 22, 2024

新一期参

For the second approach, I might need to do some things using actor.Context during initialization, so it may not work as well.

@DustOak
Copy link
Author

DustOak commented Apr 22, 2024

Currently, I am not sure if there will be any issues with the way I am doing it. The code is as follows:

func makeHook(factory BehaviorFactory, args ...any) actor.SpawnFunc {
	return func(actorSystem *actor.ActorSystem, id string, props *actor.Props, parentContext actor.SpawnerContext) (pid *actor.PID, err error) {
		hook := &hook{Behavior: factory(args...), Actor: makeActor(), factory: factory, args: args}
		wait := make(chan error)
		defer close(wait)
		fun := func(ctx actor.Context) {
			hook.update(ctx)
			hook.Errorf("--------------------------------> %s", ctx.Parent())
			hook.Do(func() {
				if err := hook.Init(hook); err != nil {
					hook.Debugf("behavior init failed: %s", err)
					hook.Exit()
					wait <- err
					return
				}
				hook.Debugf("behavior init ok.")
				wait <- nil
			})
			hook.Receive(ctx)
		}
		props = actor.PropsFromFunc(fun, actor.WithSupervisor(actor.DefaultSupervisorStrategy()))
		if pid, err = actor.DefaultSpawner(actorSystem, id, props, parentContext); err != nil {
			return nil, err
		}
		err = <-wait
		return
	}
}
func Spawn(alias Alias, factory BehaviorFactory, args ...any) (pid Pid, err error) {
	props := (&actor.Props{}).Configure(actor.WithSpawnFunc(makeHook(factory, args...)))
	if pid, err = root.ActorSystem.Root.SpawnNamed(props, string(alias)); err != nil {
		return
	}
	root.Children = append(root.Children, pid)
	return
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants