Skip to content

Instantly share code, notes, and snippets.

@Aaronontheweb
Created June 1, 2015 18:42
Show Gist options
  • Save Aaronontheweb/b69c4869ab9978681d22 to your computer and use it in GitHub Desktop.
Save Aaronontheweb/b69c4869ab9978681d22 to your computer and use it in GitHub Desktop.
Akka.NET Parent Actor "Create If Not Exist" pattern
/*
* 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;
}
}
@Aaronontheweb
Copy link
Author

Look at the CreateIfNotExist methods and where they're used, specifically

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment