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);
                }
            }
        }
Exemple #2
0
        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);
        }