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); }
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)); }
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; } } }