6

In erlang you can pass initial state to actor when spawning it. This way you don't need to deal with init messages which take actor to it's initial state again or messages needing init message arrived before. In orleans given the assumption of grains always exist you can not use constructors. Is there any way to pass initial state to grains, avoiding thus any init method which break consistency by needing it to be called before any other method?

When I say "take actor to it's initial state", I mean, in orleans context, call init method of specific grain activation twice. It is like overwriting state. May be you need this king of message which reset state but if you don't need it, it is a pitfall, a potential source of bugs.

I'm looking for some type of constructor, something like spawn(module, function, [initial state]) from erlang. My first attempt was look for any overload of GetGrain with the following signature: GrainFactory.GetGrain<IGrain>(id, initialState);

  • Maybe I misunderstand something, but you wrote: "initial state again" and "grains always exist". You should use a new grain ID for a new "first" message, and a new grain will be created with a null state. "Always exist" doesn't mean, that there is only 1 grain of a given type, it means a grain with a given ID never created or deleted manually, but the framework creates them when the given ID is first used. – lmagyar Nov 25 '15 at 21:07
  • Is `OnActivateAsync()` what you're looking for? It seems it's called whenever a grain instance is activated, so you can initialized its fields there. But I couldn't find any proper documentation for it. – svick Nov 25 '15 at 22:45
  • No, It's not what I'm looking for. OneActivateAsync() doesn't expect any parameter, It is just an event callback in order to make something when grain is activated. I'm looking for some type of constructor, something like `spawn(module, function, [initial state])` from erlang. My first attempt was look for any overload of GetGrain with the following signature: `GrainFactory.GetGrain(id, initialState);` – Guillermo Rdguez Glez Nov 27 '15 at 21:53
  • Question remains: why would you like to "reset" an existing grain's state? Why not use a new grain? To set the grain's state by the caller is impossible, the state is an internal implementation detail of the grain. But you can set a default initial state in OnActivate, when the state is null during the first activation. – lmagyar Nov 28 '15 at 09:11

2 Answers2

5

As @svick suggests, OnActivateAsync is the best approach for loading an initial state for a grain.

 public class ExampleGrain : Orleans.Grain, IExampleGrain
 {

   public override Task OnActivateAsync()
   {
        // set initial state for grain
        return base.OnActivateAsync();
    }

 ...

This method will be called every time the grain is initialised (not just the very first time). You could use the Persistence infrastructure built into Orleans to record whether the grain had been created previously (perhaps using a boolean property on your state class) i.e.

public class ExampleGrainState : GrainState
{
    public bool Initialised { get; set; }
}

[StorageProvider(ProviderName = "Storage")]
public class QuadKeyGrain : Orleans.Grain<ExampleGrainState>, IExampleGrain
{
    public override async Task OnActivateAsync()
    {
        if (!this.State.Initialised)
        {
            // do initialisation 
            this.State.Initialised = true;
            await this.WriteStateAsync();
        }
        await base.OnActivateAsync();
    }

See this tutorial for more information on persistence:

http://dotnet.github.io/orleans/Tutorials/Declarative-Persistence.html

Martin Liversage
  • 104,481
  • 22
  • 209
  • 256
Richard Astbury
  • 2,323
  • 18
  • 28
0

Grains in Orleans are always exist, so you with your approach are going to [conditionally] re-initialize the grain every time when it gets activated. Is this really what you want to be done?

Well, if you really need to initialize the specific grain to the specific state, then you can use its key (string key or string part of the key) to pass in some json. Just remember that the key has some limitations for its size.