Example #1
0
        public static async Task <(PID, ResponseStatusCode)> GetAsync(string name, string kind, CancellationToken ct)
        {
            //Check Cache
            if (PidCache.TryGetCache(name, out var pid))
            {
                return(pid, ResponseStatusCode.OK);
            }

            //Get Pid
            var address = MemberList.GetPartition(name, kind);

            if (string.IsNullOrEmpty(address))
            {
                return(null, ResponseStatusCode.Unavailable);
            }

            var remotePid = Partition.PartitionForKind(address, kind);
            var req       = new ActorPidRequest
            {
                Kind = kind,
                Name = name
            };

            try
            {
                var resp = ct == CancellationToken.None
                           ? await RootContext.Empty.RequestAsync <ActorPidResponse>(remotePid, req, Config.TimeoutTimespan)
                           : await RootContext.Empty.RequestAsync <ActorPidResponse>(remotePid, req, ct);

                var status = (ResponseStatusCode)resp.StatusCode;
                switch (status)
                {
                case ResponseStatusCode.OK:
                    PidCache.TryAddCache(name, resp.Pid);
                    return(resp.Pid, status);

                default:
                    return(resp.Pid, status);
                }
            }
            catch (TimeoutException)
            {
                return(null, ResponseStatusCode.Timeout);
            }
            catch
            {
                return(null, ResponseStatusCode.Error);
            }
        }
        private async Task Spawn(ActorPidRequest msg, IContext context)
        {
            PID pid;

            if (!_partition.TryGetValue(msg.Name, out pid))
            {
                var random = await MemberList.GetRandomActivatorAsync(msg.Kind);

                pid = await Remote.Remote.SpawnNamedAsync(random, msg.Name, msg.Kind, TimeSpan.FromSeconds(5));

                _partition[msg.Name] = pid;
            }
            context.Respond(new ActorPidResponse {
                Pid = pid
            });
        }
Example #3
0
        private async Task Spawning(ActorPidRequest req, string activator, int retryLeft, SpawningProcess spawning)
        {
            if (string.IsNullOrEmpty(activator))
            {
                activator = MemberList.GetActivator(req.Kind);
                if (string.IsNullOrEmpty(activator))
                {
                    //No activator currently available, return unavailable
                    _logger.LogDebug("No activator currently available");
                    spawning.TrySetResult(ActorPidResponse.Unavailable);
                    return;
                }
            }

            ActorPidResponse pidResp;

            try
            {
                pidResp = await Remote.Remote.SpawnNamedAsync(activator, req.Name, req.Kind, Cluster.Config.TimeoutTimespan)
                          .ConfigureAwait(false);
            }
            catch (TimeoutException)
            {
                spawning.TrySetResult(ActorPidResponse.TimeOut);
                return;
            }
            catch
            {
                spawning.TrySetResult(ActorPidResponse.Err);
                return;
            }

            if ((ResponseStatusCode)pidResp.StatusCode == ResponseStatusCode.Unavailable && retryLeft != 0)
            {
                await Spawning(req, null, --retryLeft, spawning).ConfigureAwait(false);

                return;
            }

            spawning.TrySetResult(pidResp);
        }
Example #4
0
        private void GetPid(IContext context, PidCacheRequest msg)
        {
            if (_cache.TryGetValue(msg.Name, out var pid))
            {
                context.Respond(new ActorPidResponse
                {
                    Pid = pid
                });
                return; //found the pid, replied, exit
            }

            var name = msg.Name;
            var kind = msg.Kind;

            context.ReenterAfter(MemberList.GetMemberAsync(name, kind), address =>
            {
                var remotePid = Partition.PartitionForKind(address.Result, kind);
                var req       = new ActorPidRequest
                {
                    Kind = kind,
                    Name = name
                };
                var resp = remotePid.RequestAsync <ActorPidResponse>(req);
                context.ReenterAfter(resp, t =>
                {
                    var res            = t.Result;
                    var respid         = res.Pid;
                    var key            = respid.ToShortString();
                    _cache[name]       = respid;
                    _reverseCache[key] = name;
                    context.Watch(respid);
                    context.Respond(res);
                    return(Actor.Done);
                });
                return(Actor.Done);
            });
        }
Example #5
0
        private void Spawn(ActorPidRequest msg, IContext context)
        {
            //Check if exist in current partition dictionary
            if (_partition.TryGetValue(msg.Name, out var pid))
            {
                context.Respond(new ActorPidResponse {
                    Pid = pid
                });
                return;
            }

            //Check if is spawning, if so just await spawning finish.
            SpawningProcess spawning;

            if (_spawningProcs.TryGetValue(msg.Name, out spawning))
            {
                context.ReenterAfter(spawning.Task, rst =>
                {
                    context.Respond(rst.IsFaulted ? ActorPidResponse.Err : rst.Result);
                    return(Actor.Done);
                });
                return;
            }

            //Get activator
            var activator = MemberList.GetActivator(msg.Kind);

            if (string.IsNullOrEmpty(activator))
            {
                //No activator currently available, return unavailable
                _logger.LogDebug("No members currently available");
                context.Respond(ActorPidResponse.Unavailable);
                return;
            }

            //Create SpawningProcess and cache it in spawning dictionary.
            spawning = new SpawningProcess(activator);
            _spawningProcs[msg.Name] = spawning;

            //Await SpawningProcess
            context.ReenterAfter(spawning.Task, rst =>
            {
                _spawningProcs.Remove(msg.Name);

                //Check if exist in current partition dictionary
                //This is necessary to avoid race condition during partition map transfering.
                if (_partition.TryGetValue(msg.Name, out pid))
                {
                    context.Respond(new ActorPidResponse {
                        Pid = pid
                    });
                    return(Actor.Done);
                }

                //Check if process is faulted
                if (rst.IsFaulted)
                {
                    context.Respond(ActorPidResponse.Err);
                    return(Actor.Done);
                }

                var pidResp = rst.Result;
                if ((ResponseStatusCode)pidResp.StatusCode == ResponseStatusCode.OK)
                {
                    pid = pidResp.Pid;
                    _partition[msg.Name]   = pid;
                    _reversePartition[pid] = msg.Name;
                    context.Watch(pid);
                }
                context.Respond(pidResp);
                return(Actor.Done);
            });

            //Perform Spawning
            Task.Factory.StartNew(() => Spawning(msg, activator, 3, spawning));
        }
Example #6
0
        private void GetPid(IContext context, PidCacheRequest msg)
        {
            if (_cache.TryGetValue(msg.Name, out var pid))
            {
                //found the pid, replied, exit
                context.Respond(new PidCacheResponse(pid, ResponseStatusCode.OK));
                return;
            }

            var name = msg.Name;
            var kind = msg.Kind;

            context.ReenterAfter(MemberList.GetMemberAsync(name, kind), address =>
            {
                if (string.IsNullOrEmpty(address.Result))
                {
                    context.Respond(new PidCacheResponse(null, ResponseStatusCode.Unavailable));
                    return(Actor.Done);
                }

                var remotePid = Partition.PartitionForKind(address.Result, kind);
                var req       = new ActorPidRequest
                {
                    Kind = kind,
                    Name = name
                };
                var reqTask = remotePid.RequestAsync <ActorPidResponse>(req);
                context.ReenterAfter(reqTask, t =>
                {
                    var res    = t.Result;
                    var status = (ResponseStatusCode)res.StatusCode;
                    switch (status)
                    {
                    case ResponseStatusCode.OK:
                        var key            = res.Pid.ToShortString();
                        _cache[name]       = res.Pid;
                        _reverseCache[key] = name;
                        if (_reverseCacheByMemberAddress.ContainsKey(res.Pid.Address))
                        {
                            _reverseCacheByMemberAddress[res.Pid.Address].Add(key);
                        }
                        else
                        {
                            _reverseCacheByMemberAddress[res.Pid.Address] = new HashSet <string> {
                                key
                            }
                        };

                        context.Watch(res.Pid);
                        context.Respond(new PidCacheResponse(res.Pid, status));
                        break;

                    default:
                        context.Respond(new PidCacheResponse(res.Pid, status));
                        break;
                    }
                    return(Actor.Done);
                });
                return(Actor.Done);
            });
        }
Example #7
0
        private void GetPid(IContext context, PidCacheRequest msg)
        {
            if (_cache.TryGetValue(msg.Name, out var pid))
            {
                //found the pid, replied, exit
                context.Respond(new PidCacheResponse(pid, ResponseStatusCode.OK));
                return;
            }

            var name = msg.Name;
            var kind = msg.Kind;

            var address = MemberList.GetPartition(name, kind);

            if (string.IsNullOrEmpty(address))
            {
                context.Respond(new PidCacheResponse(null, ResponseStatusCode.Unavailable));
                return;
            }

            var remotePid = Partition.PartitionForKind(address, kind);
            var req       = new ActorPidRequest
            {
                Kind = kind,
                Name = name
            };

            var reqTask = remotePid.RequestAsync <ActorPidResponse>(req, Cluster.cfg.TimeoutTimespan);

            context.ReenterAfter(reqTask, t =>
            {
                if (t.Exception != null)
                {
                    if (t.Exception.InnerException is TimeoutException)
                    {
                        //Timeout
                        context.Respond(new PidCacheResponse(null, ResponseStatusCode.Timeout));
                        return(Actor.Done);
                    }
                    else
                    {
                        //Other errors, let it throw
                        context.Respond(new PidCacheResponse(null, ResponseStatusCode.Error));
                    }
                }

                var res    = t.Result;
                var status = (ResponseStatusCode)res.StatusCode;
                switch (status)
                {
                case ResponseStatusCode.OK:
                    var key            = res.Pid.ToShortString();
                    _cache[name]       = res.Pid;
                    _reverseCache[key] = name;
                    context.Watch(res.Pid);
                    context.Respond(new PidCacheResponse(res.Pid, status));
                    break;

                default:
                    context.Respond(new PidCacheResponse(res.Pid, status));
                    break;
                }
                return(Actor.Done);
            });
        }
Example #8
0
        private async Task Spawn(ActorPidRequest msg, IContext context)
        {
            if (_partition.TryGetValue(msg.Name, out var pid))
            {
                context.Respond(new ActorPidResponse {
                    Pid = pid
                });
                return;
            }

            var activator = MemberList.GetActivator(msg.Kind);

            if (string.IsNullOrEmpty(activator))
            {
                //No activator currently available, return unavailable
                _logger.LogDebug("No members currently available");
                context.Respond(new ActorPidResponse {
                    StatusCode = (int)ResponseStatusCode.Unavailable
                });
                return;
            }

            for (var retry = 3; retry >= 0; retry--)
            {
                if (string.IsNullOrEmpty(activator))
                {
                    activator = MemberList.GetActivator(msg.Kind);
                    if (string.IsNullOrEmpty(activator))
                    {
                        //No activator currently available, return unavailable
                        _logger.LogDebug("No activator currently available");
                        context.Respond(new ActorPidResponse {
                            StatusCode = (int)ResponseStatusCode.Unavailable
                        });
                        return;
                    }
                }

                ActorPidResponse pidResp;
                try
                {
                    pidResp = await Remote.Remote.SpawnNamedAsync(activator, msg.Name, msg.Kind, Cluster.cfg.TimeoutTimespan);
                }
                catch (TimeoutException)
                {
                    context.Respond(new ActorPidResponse {
                        StatusCode = (int)ResponseStatusCode.Timeout
                    });
                    throw;
                }
                catch
                {
                    context.Respond(new ActorPidResponse {
                        StatusCode = (int)ResponseStatusCode.Error
                    });
                    throw;
                }

                switch ((ResponseStatusCode)pidResp.StatusCode)
                {
                case ResponseStatusCode.OK:
                    pid = pidResp.Pid;
                    _partition[msg.Name]   = pid;
                    _reversePartition[pid] = msg.Name;
                    context.Watch(pid);
                    context.Respond(pidResp);
                    return;

                case ResponseStatusCode.Unavailable:
                    //Get next activator to spawn
                    if (retry != 0)
                    {
                        activator = null;
                        continue;
                    }
                    context.Respond(pidResp);
                    return;

                default:
                    //Return to requester to wait
                    context.Respond(pidResp);
                    return;
                }
            }
        }
Example #9
0
        private async Task Spawn(ActorPidRequest msg, IContext context)
        {
            if (_partition.TryGetValue(msg.Name, out var pid))
            {
                context.Respond(new ActorPidResponse {
                    Pid = pid
                });
                return;
            }

            var members = await MemberList.GetMembersAsync(msg.Kind);

            if (members == null || members.Length == 0)
            {
                //No members currently available, return unavailable
                context.Respond(new ActorPidResponse {
                    StatusCode = (int)ResponseStatusCode.Unavailable
                });
                return;
            }

            var retrys = members.Length - 1;

            for (int retry = retrys; retry >= 0; retry--)
            {
                members = members ?? await MemberList.GetMembersAsync(msg.Kind);

                if (members == null || members.Length == 0)
                {
                    //No members currently available, return unavailable
                    context.Respond(new ActorPidResponse {
                        StatusCode = (int)ResponseStatusCode.Unavailable
                    });
                    return;
                }
                var activator = members[_counter.Next() % members.Length];
                members = null;

                var pidResp = await Remote.Remote.SpawnNamedAsync(activator, msg.Name, msg.Kind, TimeSpan.FromSeconds(5));

                switch ((ResponseStatusCode)pidResp.StatusCode)
                {
                case ResponseStatusCode.OK:
                    pid = pidResp.Pid;
                    _partition[msg.Name] = pid;
                    context.Watch(pid);
                    context.Respond(pidResp);
                    return;

                case ResponseStatusCode.Unavailable:
                    //Get next activator to spawn
                    if (retry != 0)
                    {
                        continue;
                    }
                    context.Respond(pidResp);
                    break;

                default:
                    //Return to requester to wait
                    context.Respond(pidResp);
                    return;
                }
            }
        }