/// <summary> /// Initializes a new instance of the BrokerStateManager class /// </summary> /// <param name="sharedData">indicating the shared data</param> /// <param name="clientAvaliable">indicating whether there is client avaliable when starting up</param> public BrokerStateManager(SharedData sharedData, bool clientAvaliable) { this.sharedData = sharedData; this.timeoutManager = new TimeoutManager("BrokerStateManager"); this.state = BrokerState.Started; this.timeoutManager.RegisterTimeout(this.sharedData.Config.Monitor.ClientConnectionTimeout, clientAvaliable ? new WaitCallback(this.TimeoutToSuspended) : new WaitCallback(this.TimeoutToFinish), null); BrokerTracing.TraceInfo("[BrokerStateManager] Successfully initialized BrokerStateManager: State = {0}", this.state); }
/// <summary> /// Initializes a new instance of the BaseResponsesHandler class /// </summary> /// <param name="queue">indicating the broker queue</param> /// <param name="action">indicating the action</param> /// <param name="timeoutManager">indicating the timeout manager</param> /// <param name="observer">indicating the observer</param> /// <param name="sharedData">indicating the shared data</param> /// <param name="version">indicating the message version</param> protected BaseResponsesHandler(BrokerQueue queue, string action, TimeoutManager timeoutManager, BrokerObserver observer, SharedData sharedData, MessageVersion version) { this.queue = queue; this.action = action; this.timeoutManager = timeoutManager; this.observer = observer; this.sharedData = sharedData; this.version = version; }
/// <summary> /// Initializes a new instance of the PullResponsesHandler class /// </summary> /// <param name="queue">indicating the broker queue</param> /// <param name="action">indicating the action</param> /// <param name="timeoutManager">indicating the timeout manager</param> /// <param name="observer">indicating the observer</param> /// <param name="sharedData">indicating the shared data</param> /// <param name="version">indicating the message version</param> public PullResponsesHandler(BrokerQueue queue, string action, TimeoutManager timeoutManager, BrokerObserver observer, SharedData sharedData, MessageVersion version) : base(queue, action, timeoutManager, observer, sharedData, version) { }
/// <summary> /// Initializes a new instance of the GetResponsesHandler class /// </summary> /// <param name="queue">indicating the broker queue</param> /// <param name="action">indicating the action</param> /// <param name="clientData">indicating the client data</param> /// <param name="clientId">indicating the client</param> /// <param name="timeoutManager">indicating the timeout manager</param> /// <param name="observer">indicating the observer</param> /// <param name="sharedData">indicating the shared data</param> /// <param name="version">indicating the message version</param> public GetResponsesHandler(BrokerQueue queue, string action, string clientData, string clientId, TimeoutManager timeoutManager, BrokerObserver observer, SharedData sharedData, MessageVersion version) : base(queue, action, timeoutManager, observer, sharedData, version) { this.clientId = clientId; this.clientData = clientData; // For now, as REST service is the only frontend on Azure. Broker can know if it is // REST service connecting by checking if broker is running on Azure. // Need to fix this logic if we reopen net.tcp frontend on Azure. if (SoaHelper.IsOnAzure()) { this.cacheBrokerQueueItem = true; } #if DEBUG // For debug purpose, if the incoming message header contains a header which // indicates it is REST service calling, also set the flag to true // This is to enable on-premise test. if (OperationContext.Current != null && OperationContext.Current.IncomingMessageHeaders.FindHeader("HpcSOAWebSvc", Constant.HpcHeaderNS) >= 0) { this.cacheBrokerQueueItem = true; } #endif }
/// <summary> /// Dispose the broker client /// </summary> /// <param name="disposing">indicating whether it is disposing</param> private void Dispose(bool disposing) { this.disposing = disposing; try { // Set state this.state = BrokerClientState.Disconnected; // Copy all the connected instances out of lock List <object> connectedList = null; lock (this.connectedInstance) { connectedList = new List <object>(this.connectedInstance.Keys); } foreach (object instance in connectedList) { try { BrokerTracing.TraceInfo("[BrokerClient] Try to close the connected instance: {0} ({1})", instance.ToString(), instance.GetHashCode()); if (instance is IDisposable) { // BrokerController ((IDisposable)instance).Dispose(); } else if (instance is IChannel) { Utility.AsyncCloseICommunicationObject((ICommunicationObject)instance); } else { Debug.Fail("[BrokerClient] Connected instance must be IDisposable or IChannel."); } } catch (Exception e) { BrokerTracing.TraceWarning("[BrokerClient] Failed to close the connected instance: {0}", e); } } if (disposing) { if (this.queue != null) { this.queue.OnEvent -= this.Queue_OnEvent; this.queue.OnPutResponsesSuccessEvent -= this.Queue_OnPutResponsesSuccessEvent; this.queue.OnFatalExceptionEvent -= this.Queue_OnFatalExceptionEvent; //for durable session, the queue is closed unless there were flushed requests, dispose if EOM was called. if (this.sharedData.BrokerInfo.Durable) { if (this.queue.FlushedRequestsCount == 0) { BrokerTracing.TraceInfo("[BrokerClient] durable session broker client {0} close the queue.", this.clientId); //if not ever flushed, reduce the count of all requests in the queue this.observer.ReduceUncommittedCounter(this.queue.AllRequestsCount); this.queue.Close(); } else if (this.endOfMessageCalled) { // Only dispose the broker queue if it is a durable session. Non-durable broker queue for // interactive session should be kept/reused and closed when closing the broker domain. // // Note (related bug #14224): logic in BrokerClient.SyncDisconnect() ensures that BrokerClient // instance will not be disposed if EndRequests is called (this.state = BrokerClientState.EndRequests). // So below code snippet could only be reached on broker entry exiting. this.observer.ReduceUncommittedCounter(this.queue.AllRequestsCount - this.queue.FlushedRequestsCount); this.queue.Dispose(); } } else //for interactive session, close the queue if EOM is not called. { if (!this.endOfMessageCalled) { BrokerTracing.TraceInfo("[BrokerClient] interactive session broker client {0} close the queue.", this.clientId); if (!this.v2ProxyClient) { //reduce the count of all unflushed requests in the queue this.observer.ReduceUncommittedCounter(this.queue.AllRequestsCount - this.queue.FlushedRequestsCount); } this.queue.Close(); } } this.queue = null; this.batchMessageIds.Clear(); } } if (this.responsesClient != null) { this.responsesClient.Dispose(); this.responsesClient = null; } if (this.timeoutManager != null) { this.timeoutManager.Dispose(); this.timeoutManager = null; } // do not dispose this.lockForDiscardRequests for this may block the threads in the write queue, which may lead to the hang when broker entry exits. // do not dispose this.batchIdChangedEvent for any wait for the event would hang } catch (Exception e) { BrokerTracing.TraceWarning("[BrokerClient] Exception thrown while disposing: {0}", e); } }
/// <summary> /// Initializes a new instance of the BrokerClient class /// </summary> /// <param name="clientId">indicating the client Id</param> /// <param name="userName">indicating the user name</param> /// <param name="queueFactory">indicating the queue factory</param> /// <param name="observer">indicating the observer</param> /// <param name="stateManager">indicating the state manager</param> /// <param name="monitor">indicating the monitor</param> /// <param name="sharedData">indicating the shared data</param> public BrokerClient(string clientId, string userName, BrokerQueueFactory queueFactory, BrokerObserver observer, BrokerStateManager stateManager, ServiceJobMonitorBase monitor, SharedData sharedData) { bool isNewCreated; // Set the "signletonInstanceConnected" property if // SessionStartInfo.AutoDisposeBrokerClient is set. This property is only possibly to // be set to true after if HTTP transport scheme is specified. And it is by design so. if (sharedData.StartInfo.AutoDisposeBrokerClient.HasValue) { this.singletonInstanceConnected = !sharedData.StartInfo.AutoDisposeBrokerClient.Value; } this.clientId = clientId; this.v2ProxyClient = clientId.StartsWith(FrontEndBase.DefaultClientPrefix); this.sharedData = sharedData; this.observer = observer; this.monitor = monitor; this.stateManager = stateManager; this.stateManager.OnFailed += new BrokerStateManager.SessionFailedEventHandler(this.StateManager_OnFailed); try { this.queue = queueFactory.GetPersistQueueByClient(clientId, userName, out isNewCreated); } catch (BrokerQueueException e) { // Catch the exception about the username not match and translte it to session fault if (e.ErrorCode == (int)BrokerQueueErrorCode.E_BQ_USER_NOT_MATCH) { ThrowHelper.ThrowSessionFault(SOAFaultCode.AccessDenied_BrokerQueue, SR.AccessDenied_BrokerQueue, clientId, userName); } else { throw; } } this.queue.OnEvent += new BrokerQueueEventDelegate(this.Queue_OnEvent); this.queue.OnPutResponsesSuccessEvent += new EventHandler <PutResponsesSuccessEventArgs>(this.Queue_OnPutResponsesSuccessEvent); this.queue.OnFatalExceptionEvent += new EventHandler <ExceptionEventArgs>(this.Queue_OnFatalExceptionEvent); this.timeoutManager = new TimeoutManager("BrokerClient " + clientId); BrokerTracing.EtwTrace.LogBrokerClientCreated(this.sharedData.BrokerInfo.SessionId, clientId); if (this.queue.IsAllRequestsProcessed || monitor.ServiceJobState == ServiceJobState.Finished) { // If the queue has processed all the request or the service job is finished, the broker client can only get responses this.state = BrokerClientState.GetResponse; this.endOfMessageCalled = true; BrokerTracing.EtwTrace.LogBrokerClientStateTransition(this.sharedData.BrokerInfo.SessionId, this.clientId, "GetResponse"); this.timeoutManager.RegisterTimeout(this.sharedData.Config.Monitor.ClientIdleTimeout, this.TimeoutToDisconnected, this.state); } else { if (!this.queue.EOMReceived) { // If EndOfMessage is not received, the client is in the ClientConnected state and is ready to accept messages this.state = BrokerClientState.ClientConnected; BrokerTracing.EtwTrace.LogBrokerClientStateTransition(this.sharedData.BrokerInfo.SessionId, this.clientId, "ClientConnected"); this.timeoutManager.RegisterTimeout(this.sharedData.Config.Monitor.ClientIdleTimeout, this.TimeoutToDisconnected, this.state); } else { // If EndOfMessage has been received, the client is in the EndOfMessage state and does not accept any more requests. this.state = BrokerClientState.EndRequests; this.endOfMessageCalled = true; BrokerTracing.EtwTrace.LogBrokerClientStateTransition(this.sharedData.BrokerInfo.SessionId, this.clientId, "EndOfMessage"); } } }