在 Microsoft Orleans 中通过 GUID 检查谷物是否存在
Check if grain exists by GUID in Microsoft Orleans
你如何检查特定 ID 的 grain 是否已经存在?
考虑到下面将创建一个新的玩家谷物,如果它不存在,我传递给 GetGrain()
,我不确定如何检查它是否已经存在。
public async Task<Guid> Create(Guid playerGuid)
{
var player = GrainClient.GrainFactory.GetGrain<IPlayerGrain>(playerGuid);
var gameGuid = await player.CreateGame();
return gameGuid;
}
简短的回答是存储一些状态,以便 grain 知道它之前是否已被激活。
Orleans 中的 Grains 从未明确创建或销毁:它们始终可用于处理请求。因此,从技术上讲,谷物是否存在的概念不适用于奥尔良。另一方面,我们可以问 "has a grain with this id ever been activated before".
您可能需要检查两种情况:
- grain 从未被激活,但你期望它被激活。例如:我正在
IPlayerGrain
上调用一个方法,但播放器不存在。
- grain 之前已被激活,但您期望它没有。例如:我正在尝试为该玩家创建一个新游戏,但该 ID 已被占用。
在下面的代码示例中,您可以看到两种情况:
- 如果以前从未创建过播放器,则对
IPlayerGrain.CreateGame()
的调用将抛出异常。忽略我从未设置 Created
的事实,这可以通过某些 CreatePlayer(...)
方法完成。
- 如果游戏已经创建,则调用
IGameGrain.TryCreateGame(player)
returns false。在这种情况下,IPlayerGrain.CreateGame()
将继续循环,直到找到尚未创建的游戏。使用 Guid
id,您不太可能会看到碰撞,但我理解谨慎的愿望 - 以防万一星星对齐并合谋反对您。
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
方法不需要改变。
你如何检查特定 ID 的 grain 是否已经存在?
考虑到下面将创建一个新的玩家谷物,如果它不存在,我传递给 GetGrain()
,我不确定如何检查它是否已经存在。
public async Task<Guid> Create(Guid playerGuid)
{
var player = GrainClient.GrainFactory.GetGrain<IPlayerGrain>(playerGuid);
var gameGuid = await player.CreateGame();
return gameGuid;
}
简短的回答是存储一些状态,以便 grain 知道它之前是否已被激活。
Orleans 中的 Grains 从未明确创建或销毁:它们始终可用于处理请求。因此,从技术上讲,谷物是否存在的概念不适用于奥尔良。另一方面,我们可以问 "has a grain with this id ever been activated before".
您可能需要检查两种情况:
- grain 从未被激活,但你期望它被激活。例如:我正在
IPlayerGrain
上调用一个方法,但播放器不存在。 - grain 之前已被激活,但您期望它没有。例如:我正在尝试为该玩家创建一个新游戏,但该 ID 已被占用。
在下面的代码示例中,您可以看到两种情况:
- 如果以前从未创建过播放器,则对
IPlayerGrain.CreateGame()
的调用将抛出异常。忽略我从未设置Created
的事实,这可以通过某些CreatePlayer(...)
方法完成。 - 如果游戏已经创建,则调用
IGameGrain.TryCreateGame(player)
returns false。在这种情况下,IPlayerGrain.CreateGame()
将继续循环,直到找到尚未创建的游戏。使用Guid
id,您不太可能会看到碰撞,但我理解谨慎的愿望 - 以防万一星星对齐并合谋反对您。
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
方法不需要改变。