private void InvokeProcessRequestAsync <TRequestType, TResult>(TaskCompletionSource <TResult> taskProducer, StatefulServiceExecutionContext executionContext, string methodName, Tuple <Type, Type[], object[]> methodParams) { Exception exception = null; try { if (!typeof(IProcessHttpRequest).IsAssignableFrom(typeof(TRequestType)) && !typeof(IProcessTcpRequest).IsAssignableFrom(typeof(TRequestType))) { taskProducer.SetException(new NotSupportedException("Method not supported by the server")); return; } // Get Session Information StatefulProgramInstance instance = null; DateTime expiryTime; IComparable sessionId; object sessionObj = null; HttpListenerContext httpListenerContext = methodParams.Item3[methodParams.Item3.Length - 1] as HttpListenerContext; if (httpListenerContext != null) { sessionObj = httpListenerContext.Request; } else { // For TCP we smuggle the headers in IDictionary<string, string> passed via asyncState StreamWrapper streamWrapper = methodParams.Item3[methodParams.Item3.Length - 1] as StreamWrapper; sessionObj = streamWrapper != null ? streamWrapper.UserData : null; } if (!StatefulServiceReplica <TInstance> .GetSessionInformation(sessionObj, out sessionId, out expiryTime)) { // TODO: We do not support session expiry currently sessionId = Helpers.GenerateUniqueId(); expiryTime = DateTime.UtcNow.AddYears(100); } else { instance = this.instanceManager.GetInstance(sessionId); } // Create a new instance if necessary bool setSessionInformation = false; bool isExpired = sessionId != null && DateTime.UtcNow > expiryTime; if (instance == null) { this.CreateInstance(sessionId, null); instance = this.instanceManager.GetInstance(sessionId); setSessionInformation = true; } Action <Task> processRequestContinuation = delegate(Task task) { this.Invoke <StatefulServiceExecutionContext>( (cec) => { Exception exception1 = null; try { if (setSessionInformation) { if (httpListenerContext != null) { sessionObj = httpListenerContext.Response; } else { // For TCP we smuggle the headers in asyncObject sessionObj = (IDictionary <string, string>)methodParams.Item3[methodParams.Item3.Length - 1]; } StatefulServiceReplica <TInstance> .SetSessionInformation(sessionObj, sessionId, expiryTime); } if (!task.IsFaulted) { // Get the result from either the http task or task returned by Replicable method invocation. object result = null; if (typeof(IProcessTcpRequest).IsAssignableFrom(typeof(TRequestType))) { Task <Stream> tcpResponseTask = task as Task <Stream>; if (tcpResponseTask != null) { result = tcpResponseTask.Result; } else { Task <object> taskWithObj = task as Task <object>; result = (Stream)taskWithObj.Result; } } taskProducer.SetResult((TResult)result); } else { exception1 = task.Exception.InnerException ?? task.Exception; } if (isExpired) { this.DeleteInstance(sessionId); } } catch (Exception e) { AppTrace.TraceException(e, "StatefulServiceReplicaT.InvokeProcessRequestAsync"); exception1 = e; } finally { if (exception1 != null) { taskProducer.SetException(exception1); } } }); }; if (instance != null && !isExpired) { IEnumerable <ReplicableMethodInfo> matchingMethods = null; instance.TypeInfo.TryGetMatchingMethod("ProcessRequestAsync", methodParams.Item1, methodParams.Item2, out matchingMethods); int matchingMethodCount = matchingMethods != null?matchingMethods.Count() : 0; if (matchingMethodCount == 1 && matchingMethods.First().Type == ReplicableMethodInfo.MethodType.AsyncTask) { ReplicableMethodInfo methodInfo = matchingMethods.First(); Task <Tuple <object, object[]> > asyncInvocationTask = instance.InvokeAsync(methodInfo.Methods[0], methodParams.Item3); asyncInvocationTask.Wait(); Task task = (Task)asyncInvocationTask.Result.Item1; task.ContinueWith(processRequestContinuation); } else if (matchingMethodCount > 1) { exception = new AmbiguousMatchException(String.Format(CultureInfo.InvariantCulture, "Multiple methods with name '{0}' matching similar parameters were found", "ProcessRequestAsync")); } else if (typeof(IProcessHttpRequest).IsAssignableFrom(typeof(TRequestType))) { ((IProcessHttpRequest)instance.Instance).ProcessRequestAsync((HttpListenerContext)methodParams.Item3[0]) .ContinueWith(task => { processRequestContinuation(task); }, TaskContinuationOptions.ExecuteSynchronously); } else { ((IProcessTcpRequest)instance.Instance).ProcessRequestAsync((Stream)methodParams.Item3[0]) .ContinueWith(task => { processRequestContinuation(task); }, TaskContinuationOptions.ExecuteSynchronously); } } else { AppTrace.TraceMsg(TraceLogEventType.Warning, "StatefulServiceReplicaT.InvokeProcessRequestAsync", "Instance cannot be created for expired session cookie with session id '{0}'.", sessionId); taskProducer.SetException(new InvalidOperationException("Instance expired. Service cannot process request")); } } catch (Exception e) { AppTrace.TraceException(e, "StatefulServiceReplicaT.InvokeProcessRequestAsync"); exception = e; } finally { if (exception != null) { taskProducer.SetException(exception); } } }
internal Replica GetSelectedReplica(Replica[] results, Random random, bool skipReplicasNotUp) { if (results.Length == 0) { throw new FabricInvalidReplicaSelectorException(); } // Filtered set is for when random/primary or secondary need to be selected to ensure no idle/down replicas are in selection List <Replica> filteredResults = new List <Replica>(); foreach (Replica result in results) { if (!this.IsInvalidReplica(result.ReplicaStatus) || !skipReplicasNotUp) { filteredResults.Add(result); } } Replica replicaResult = null; switch (this.selectorType) { case ReplicaSelectorType.Primary: foreach (Replica result in filteredResults) { StatefulServiceReplica statefulResult = result as StatefulServiceReplica; if (statefulResult == null) { throw new FabricException(FabricErrorCode.ServiceTypeMismatch); } if (statefulResult.ReplicaRole == ReplicaRole.Primary) { replicaResult = result; break; } } break; case ReplicaSelectorType.RandomSecondary: List <Replica> secondaries = new List <Replica>(); foreach (Replica result in filteredResults) { StatefulServiceReplica statefulResult = result as StatefulServiceReplica; if (statefulResult == null) { throw new FabricException(FabricErrorCode.ServiceTypeMismatch); } if (statefulResult.ReplicaRole == ReplicaRole.ActiveSecondary) { secondaries.Add(result); } } if (secondaries.Count == 0) { throw new FabricInvalidReplicaSelectorException(StringResources.Error_NoSecondariesInReplicaSet, FabricErrorCode.InvalidReplicaSelector); } int secondaryIndex = random.Next(secondaries.Count); replicaResult = secondaries[secondaryIndex]; break; case ReplicaSelectorType.ReplicaId: // If specific replica is targeted we search for it in original result rather than filtered set foreach (Replica result in results) { if (result.Id == this.replicaOrInstanceId) { replicaResult = result; } } break; case ReplicaSelectorType.Random: int index = random.Next(filteredResults.Count); replicaResult = filteredResults[index]; break; default: break; } // replace this string with toString() overload. if (replicaResult == null) { throw new FabricException(StringHelper.Format(StringResources.Error_ReplicaNotFoundForSelector, this.selectorType, this.replicaOrInstanceId), FabricErrorCode.ReplicaDoesNotExist); } return(replicaResult); }