Created
June 1, 2015 18:42
-
-
Save Aaronontheweb/b69c4869ab9978681d22 to your computer and use it in GitHub Desktop.
Akka.NET Parent Actor "Create If Not Exist" pattern
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* From Petabridge's Akka.Remote training: https://petabridge.com/training/akka-remoting/ | |
* Copyright Petabridge LLC, 2015. | |
*/ | |
/// <summary> | |
/// Master actor responsible for the management of friends lists | |
/// </summary> | |
public class FriendsMaster : ReceiveActor | |
{ | |
#region Message classes | |
public class GetFriendActorRef | |
{ | |
public GetFriendActorRef(string userName) | |
{ | |
UserName = userName; | |
} | |
public string UserName { get; private set; } | |
} | |
public class RestartFailed | |
{ | |
public RestartFailed(string userName, IActorRef failedChild) | |
{ | |
FailedChild = failedChild; | |
UserName = userName; | |
} | |
public string UserName { get; private set; } | |
public IActorRef FailedChild { get; private set; } | |
} | |
public class RecreateChild | |
{ | |
public RecreateChild(string userName) | |
{ | |
UserName = userName; | |
} | |
public string UserName { get; private set; } | |
} | |
#endregion | |
private readonly IActorRef _presenceActor; | |
private readonly IActorRef _identityActor; | |
private readonly Func<string, Props> _friendListPropsFactory; | |
public FriendsMaster(IActorRef presenceActor, IActorRef identityActor, Func<string, Props> friendListPropsFactory) | |
{ | |
_presenceActor = presenceActor; | |
_friendListPropsFactory = friendListPropsFactory; | |
_identityActor = identityActor; | |
// Warm up all of the persistent friends list actors | |
// and warm the presence actor | |
Receive<IEnumerable<ExistingUser>>(users => | |
{ | |
foreach (var user in users) | |
{ | |
CreateIfNotExist(Context, user.DisplayName); | |
//warm up the presence actor | |
_presenceActor.Tell(new PresenceActor.InitialPresence(user.DisplayName)); | |
} | |
}); | |
Receive<RestartFailed>(child => | |
{ | |
Context.Stop(child.FailedChild); | |
Context.System.Scheduler.ScheduleTellOnce(GetRandomRestartTime(), Self, new RecreateChild(child.UserName), Self); | |
}); | |
Receive<RecreateChild>(child => CreateIfNotExist(Context, child.UserName)); | |
Receive<AddFriend>(friend => | |
{ | |
if (friend.Friend.Equals(friend.Requestor)) | |
{ | |
Sender.Tell(new AddFriendRequestFailed(friend, "You can't be your own friend.")); | |
} | |
else | |
{ | |
var sender = Sender; //need to close over Sender for TPL continuations | |
var context = Context; //also need to close over local actor context | |
var verifyFriend = _identityActor.Ask<UserIdentity>(new FetchUserByName(friend.Friend)); | |
var verifyRequestor = _identityActor.Ask<UserIdentity>(new FetchUserByName(friend.Requestor)); | |
Task.WhenAll(verifyFriend, verifyRequestor).ContinueWith(tr => | |
{ | |
//check to see if we could find the missing users | |
if (tr.Result.Any(x => x is MissingUserIdentity)) | |
{ | |
sender.Tell(new AddFriendRequestFailed(friend, | |
string.Format( | |
"User {0} or user {1} was not found." + Environment.NewLine + | |
" No imaginary friends!", | |
friend.Requestor, friend.Friend)), context.Self); | |
} | |
else | |
{ | |
var reverse = friend.Reverse(); | |
CreateIfNotExist(context, friend.Requestor).Tell(friend); | |
CreateIfNotExist(context, friend.Friend).Tell(reverse); | |
} | |
}); | |
} | |
}); | |
Receive<RemoveFriend>(friend => | |
{ | |
var reverse = friend.Reverse(); | |
CreateIfNotExist(Context, friend.Requestor).Tell(friend); | |
CreateIfNotExist(Context, reverse.Requestor).Tell(reverse); | |
}); | |
Receive<GetFriendActorRef>(friend => | |
{ | |
var actor = CreateIfNotExist(Context, friend.UserName); | |
Sender.Tell(actor); | |
}); | |
Receive<SubscribeFriends>(friends => | |
{ | |
var actor = CreateIfNotExist(Context, friends.UserName); | |
actor.Forward(friends); | |
}); | |
Receive<UnsubscribeFriends>(friends => | |
{ | |
var actor = CreateIfNotExist(Context, friends.UserName); | |
actor.Forward(friends); | |
}); | |
Receive<GetFriends>(friends => | |
{ | |
var actor = CreateIfNotExist(Context, friends.UserName); | |
actor.Forward(friends); | |
}); | |
} | |
private TimeSpan GetRandomRestartTime() | |
{ | |
var rng = (ThreadLocalRandom.Current.NextDouble()*(1.5)) + 1.0; | |
return TimeSpan.FromSeconds(rng); | |
} | |
private IActorRef CreateIfNotExist(IActorContext context, string userName) | |
{ | |
var child = context.Child(userName); | |
if (child.Equals(ActorRefs.Nobody)) | |
{ | |
return context.ActorOf(_friendListPropsFactory(userName), userName); | |
} | |
return child; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Look at the
CreateIfNotExist
methods and where they're used, specifically