7

您如何检查特定 ID 是否已经存在颗粒?

GetGrain()考虑到下面将创建一个新的玩家颗粒,如果它不存在,我传入的 Id ,我不知道如何检查一个是否已经存在。

public async Task<Guid> Create(Guid playerGuid)
    {
        var player = GrainClient.GrainFactory.GetGrain<IPlayerGrain>(playerGuid);
        var gameGuid = await player.CreateGame();

        return gameGuid;
    }
4

1 回答 1

12

简短的回答是存储一些状态,这样grain就知道它之前是否被激活过。

Orleans 的 Grains 从未显式创建或销毁:它们始终可用于处理请求。因此,从技术上讲,谷物是否存在的概念不适用于奥尔良。另一方面,我们可以询问“以前是否曾激活过具有此 id 的颗粒”。

您可能需要检查两种情况:

  1. 谷物从未被激活,但你期待它已经激活。例如:我正在调用一个方法IPlayerGrain,但播放器不存在。
  2. 谷物先前已被激活,但您期望它尚未激活。例如:我正在尝试为该玩家创建一个新游戏,但该 id 已被占用。

在下面的代码示例中,您可以看到这两种情况:

  1. IPlayerGrain.CreateGame()如果之前从未创建过播放器,则调用将引发异常。忽略我从不设置的事实Created,这可以通过某种CreatePlayer(...)方法完成。
  2. IGameGrain.TryCreateGame(player)如果游戏已经创建,则调用返回 false。在这种情况下,IPlayerGrain.CreateGame()将继续循环,直到找到尚未创建的游戏。有了Guid身份证,你不太可能看到碰撞,但我理解谨慎的愿望 - 以防万一星星对齐并密谋反对你。
public interface IPlayerGrain : IGrainWithGuidKey
{
    Task<Guid> CreateGame();
}

public class PlayerState
{
    public bool Created { get; set; }
}

public class PlayerGrain : Grain<PlayerState>, IPlayerGrain
{
    public async Task<Guid> CreateGame()
    {
        if (!this.State.Created)
          throw new InvalidOperationException("Player does not exist.");

        var thisPlayer = this.AsReference<IPlayerGrain>();

        var created = false;
        var gameId = default(Guid);
        while (!created)
        {
            // Get a new, random game grain
            gameId = Guid.NewGuid();

            // Try to create a game.
            created = await this.GrainFactory.GetGrain<IGameGrain>(gameId)
                                .TryCreateGame(thisPlayer);

            // If the game was successfully created, break out and return the id.
            // Otherwise, keep looping.
        }

        return gameId;
    }
}
public interface IGameGrain : IGrainWithGuidKey
{
    // Returns true if game was created, false otherwise.
    Task<bool> TryCreateGame(IPlayerGrain player);
}

public class GameState
{
    public IPlayerGrain Player { get; set; }
}

public class GameGrain : Grain<GameState>, IGameGrain
{
    public async Task<bool> TryCreateGame(IPlayerGrain player)
    {
        // If this grain already has a player, return false.
        if (this.State.Player != null) return false;

        // Otherwise, set the player, write it to storage, and return true.
        this.State.Player = player;
        await this.WriteStateAsync();
        return true;
    }
}

您问题中的Create方法不需要更改。

于 2017-05-02T21:41:26.563 回答