public Boolean CanProcessMessage(ActorRequest message) { if (_actorMap.TryGetValue(message.ActorInterface, out var actorType)) { return(HasInstanceFor(actorType, message.ActorId)); } return(false); }
public async Task <ActorResponse> SendActorRequest(ActorRequest request, TimeSpan?timeout = null) { timeout = timeout ?? TimeSpan.FromMilliseconds(-1); if (_localStage.Enabled) { //we are inside a stage, forward to server if (request.FireAndForget) { await _stageServer.ReceivedActorRequest(request, null); return(new ActorResponse() { Success = true }); } else { var semaphore = new SemaphoreSlim(0, 1); var queueItem = _localResponseBuffer[request.Id] = new Tuple <SemaphoreSlim, ActorResponse>(semaphore, null); try { await _stageServer.ReceivedActorRequest(request, null); var responseArrived = await semaphore.WaitAsync(timeout.Value); if (responseArrived) { if (_localResponseBuffer.TryRemove(request.Id, out queueItem)) { if (queueItem.Item2 != null) { return(queueItem.Item2); } } } _localResponseBuffer.TryRemove(request.Id, out _); throw new TimeoutException(); } finally { } } } else { //we are on a pure client return(await SendRemoteActorRequest(request, timeout)); } }
public async Task <ActorResponse> Execute(ActorRequest message, TimeSpan?timeout = null) { _reqSecondMeter.Tick(); var actorInstanceKey = string.Join(",", message.ActorInterface, message.ActorId); var actorInstance = await ActivateInstance(message.ActorInterface, message.ActorId); actorInstance.LastAccess = DateTimeOffset.UtcNow; var track = _serviceOptions.TrackActorExecutionDependencyCalls ? _telemetry.Dependency($"actor:{message.ActorInterface}", message.ActorMethodName) : null; try { var result = await actorInstance.Instance.Post(_serializer, message, timeout); track?.End(true); var response = new ActorResponse() { Success = true, Response = _serializer.Serialize(result), Id = message.Id }; return(response); } catch (Exception ex) { track?.End(false); var response = new ActorResponse() { Success = false, //Exception = (Exception)ex, Id = message.Id }; _actorInstances.TryRemove(actorInstanceKey, out var instance); instance.Instance.Dispose(); await _actorDirectory.UnregisterActor(instance.ActorTypeName, instance.ActorId, this.StageGuid); _telemetry.Exception(ex, "ActorException"); return(response); } }
public async Task <ActorResponse> SendRemoteActorRequest(String stageId, ActorRequest request, TimeSpan?timeout = null) { if (request is LocalActorRequest) { request = ((LocalActorRequest)request).ToRemote(_serializer); } var message = new RemoteStageMessage() { ActorRequest = request, MessageType = RemoteMessageType.ActorRequest }; if (request.FireAndForget) { await _socketClient.SendRequest(stageId, _serializer.Serialize(message)); return(new ActorResponse() { Success = true }); } else { var semaphore = new SemaphoreSlim(0, 1); var queueItem = _serverResponseBuffer[request.Id] = new Tuple <SemaphoreSlim, ActorResponse>(semaphore, null); try { await _socketClient.SendRequest(stageId, _serializer.Serialize(message)); var responseArrived = await semaphore.WaitAsync(timeout ?? TimeSpan.FromMilliseconds(-1)); if (responseArrived) { if (_serverResponseBuffer.TryRemove(request.Id, out queueItem)) { return(queueItem.Item2); } } throw new TimeoutException(); } finally { _serverResponseBuffer.TryRemove(request.Id, out _); } } }
public async Task <ActorResponse> SendRemoteActorRequest(ActorRequest request, TimeSpan?timeout = null) { if (request.WorkerActor) { var allStages = await _stageDirectory.GetAllStages(); var stageAddress = allStages.OrderBy(a => Guid.NewGuid()).FirstOrDefault(); return(await SendRemoteActorRequest(stageAddress, request, timeout)); } else { var stageResponse = await _actorDirectory.GetAddress(request.ActorInterface, request.ActorId); if (await _stageDirectory.IsLive(stageResponse.StageId)) { return(await SendRemoteActorRequest(stageResponse.StageId, request, timeout)); } else { return(await SendRemoteActorRequest(null, request, timeout)); } } }
public ActorRequest ToRemote(ITransportSerializer _serializer) { var request = new ActorRequest(); List <byte[]> arguments = new List <byte[]>(); foreach (var argument in this.ArgumentObjects) { arguments.Add(_serializer.Serialize(argument)); } request.Arguments = arguments; request.ActorInterface = this.ActorInterface; request.ActorMethodName = this.ActorMethod.Name; request.ActorId = this.ActorId; request.FireAndForget = this.FireAndForget; request.FromClient = this.FromClient; request.Id = this.Id; request.WorkerActor = this.WorkerActor; return(request); }
protected async Task ProcessActorRequestLocally(ActorRequest message, string sourceStageId) { ActorResponse response = null; try { response = await _localStage.Execute(message); } catch (Exception ex) { response = new ActorResponse() { Id = message.Id, //Exception = ex, Success = false }; _telemetry.Exception(ex, "ProcessActorRequestLocally"); } if (!message.FireAndForget) { await this.SendActorResponse(sourceStageId, response); } }
public async Task <object> Post(ITransportSerializer serializer, ActorRequest message, TimeSpan?timeout = null, CancellationToken?ct = null) { var key = $"{_typeName}.{message.ActorMethodName}"; if (!_methodCache.TryGetValue(key, out var method)) { method = this.GetType().GetMethod(message.ActorMethodName); _methodCache.TryAdd(key, method); } //timeout attribute var timeoutAttribute = method.GetCustomAttribute <MethodTimeoutAttribute>(); if (timeoutAttribute != null) { timeout = timeoutAttribute.Timeout; } else { timeout = timeout ?? TimeSpan.FromSeconds(_options.DefaultActorMethodTimeout); } var parameters = method.GetParameters(); //wire parameters List <object> arguments = new List <object>(); if (message is LocalActorRequest) { var localMessage = (LocalActorRequest)message; for (var i = 0; i < parameters.Length; i++) { var parameterInfo = parameters[i]; if (localMessage.ArgumentObjects.Length > i) { arguments.Add(localMessage.ArgumentObjects[i]); } else { arguments.Add(Type.Missing); } } } else { for (var i = 0; i < parameters.Length; i++) { var parameterInfo = parameters[i]; if (message.Arguments.Count > i) { arguments.Add(serializer.Deserialize(parameterInfo.ParameterType, message.Arguments[i])); } else { arguments.Add(Type.Missing); } } } Task workTask = null; var sync = method.GetCustomAttribute <AllowParallel>(true) == null; if (sync) { Interlocked.Increment(ref _queueCount); { if (timeout.HasValue) { var sw = Stopwatch.StartNew(); //try to acquire lock var asyncLock = await _executionLock.LockAsync(timeout.Value); if (asyncLock == null) { throw new TimeoutException(); } try { sw.Stop(); //try to run method var timeoutTask = Task.Delay(timeout.Value - sw.Elapsed); workTask = (Task)method.Invoke(this, arguments.ToArray()); await Task.WhenAny(workTask, timeoutTask); if (timeoutTask.IsCompleted && !workTask.IsCompleted) { throw new TimeoutException(); } } finally { if (asyncLock != null) { asyncLock.Dispose(); } } } else { var asyncLock = await _executionLock.LockAsync(); workTask = (Task)method.Invoke(this, arguments.ToArray()); await workTask; if (asyncLock != null) { asyncLock.Dispose(); } } Interlocked.Decrement(ref _queueCount); } } else { workTask = (Task)method.Invoke(this, arguments.ToArray()); } if (!_returnPropertyCache.TryGetValue(key, out var resultProperty)) { if (method.ReturnType.IsConstructedGenericType) { resultProperty = workTask.GetType().GetProperty("Result"); _returnPropertyCache.TryAdd(key, resultProperty); } else { _returnPropertyCache.TryAdd(key, null); } } if (resultProperty != null && workTask != null) { var result = resultProperty.GetValue(workTask); return(result); } else { return(null); } }
public async Task ReceivedActorRequest(ActorRequest message, string sourceStageId) { if (_localStage == null || !_localStage.Enabled) { //we are inside a client, no point on getting actor requests _exitSemaphore.Release(); return; } if (message.WorkerActor) { await ProcessActorRequestLocally(message, sourceStageId); return; } if (_localStage.CanProcessMessage(message)) { //we already have a local instance await ProcessActorRequestLocally(message, sourceStageId); return; } //query the directory var queryResult = await _actorDirectory.GetAddress(message.ActorInterface, message.ActorId); if (queryResult.Found) { if (queryResult.StageId == _localStage.StageGuid) { //instance already registered on this stage but not active await ProcessActorRequestLocally(message, sourceStageId); return; } else { if (await _stageDirectory.IsLive(queryResult.StageId)) { //proxy request to the right stage var remoteResponse = await _remoteClient.Value.SendRemoteActorRequest(queryResult.StageId, message); if (!message.FireAndForget) { await this.SendActorResponse(sourceStageId, remoteResponse); } } else { //reallocate the actor var newStageId = await _actorDirectory.Reallocate(message.ActorInterface, message.ActorId, queryResult.StageId); //try again await ReceivedActorRequest(message, sourceStageId); } } } else { //reallocate the actor var newStageId = await _actorDirectory.Reallocate(message.ActorInterface, message.ActorId, queryResult.StageId); //try again await ReceivedActorRequest(message, sourceStageId); } }
public async Task <object> Post(ITransportSerializer serializer, ActorRequest message, TimeSpan?timeout = null, CancellationToken?ct = null) { if (_taskScheduler == null) { return(null); } try { var key = $"{this.GetType().Name}.{message.ActorMethodName}"; if (!_methodCache.TryGetValue(key, out var method)) { method = this.GetType().GetMethod(message.ActorMethodName); _methodCache.TryAdd(key, method); } var parameters = method.GetParameters(); List <object> arguments = new List <object>(); for (var i = 0; i < message.Arguments.Count; i++) { var parameterInfo = parameters[i]; arguments.Add(serializer.Deserialize(parameterInfo.ParameterType, message.Arguments[i])); } var taskResult = await Task.Factory.StartNew(async() => { Task workTask = (Task)method.Invoke(this, arguments.ToArray()); await workTask; return(workTask); }, ct ?? CancellationToken.None, TaskCreationOptions.None, _taskScheduler); var doneTask = taskResult.Result; if (!_returnPropertyCache.TryGetValue(key, out var resultProperty)) { if (method.ReturnType.IsConstructedGenericType) { resultProperty = doneTask.GetType().GetProperty("Result"); _returnPropertyCache.TryAdd(key, resultProperty); } else { _returnPropertyCache.TryAdd(key, null); } } if (resultProperty != null) { var result = resultProperty.GetValue(doneTask); return(result); } else { return(null); } } catch (Exception ex) { if (ex.InnerException != null) { return(ex.InnerException); } else { return(ex); } } }