/// <summary> /// The callback method that scans the pool for any end-of-life channels and purges them /// from the pool. This routine does not hold any locks so has to be pretty resilient about /// accessing and disposing of the channels which may well be used or removed at the time the /// cleanup occurs. /// </summary> //private void PoolCleanup(object sender, ElapsedEventArgs e) private void PoolCleanup() { Debug.WriteLine("in PoolCleanup event...."); while (_runCleanupTask) { Thread.Sleep(Config.CleanupInterval * 1000); int currentChannelCount = 0; lock (_repopulateThread) { DebugMessage("Cleanup process is checking pool status"); if (_channelList.Count > 0) { int latestCount = _channelList.Count - 1; for (int cnt = latestCount; cnt >= 0; cnt--) { try { ChannelContext <TChannel> ch = _channelList[cnt]; if (IsChannelExpired(ch)) { DebugMessage( string.Format( "channel found that needs to be removed. ChannelOpened:{0}, Current Time:{1}", ch.DateTimeOpened.ToShortTimeString(), DateTime.Now.ToShortTimeString())); // needs to be purged. try { _channelList.RemoveAt(cnt); currentChannelCount++; if (((ICommunicationObject)ch.Channel).State == CommunicationState.Opened || ((ICommunicationObject)ch.Channel).State == CommunicationState.Created) { ((ICommunicationObject)ch.Channel).Close(); } } catch (CommunicationException ce) { // do nothing here as well, the channel was already in a faulted state. DebugMessage("Channel to be removed was already in a faulted state"); } catch (Exception ex) { // To get here means the number of channels in the pool was exhaused in between accessing the // initial element, so we leave things as they are and let the asynch process refill the pool. DebugMessage("Unable to remove channel. [" + ex.Message + "]"); } } } catch { // and again, we dont care if we are out of range continue; } } } } // Fire the ChannelPoolCollected event. ChannelPoolCollectedEventArgs cpea = new ChannelPoolCollectedEventArgs(currentChannelCount); OnChannelPoolCollected(cpea); } }
/// <summary> /// The simple routine to refill the channel pool with opened channels. /// </summary> private void RefillPool(bool withLock) { DebugMessage("In RefillPool action"); bool inSync = false; ChannelContext <TChannel> chanContext = null; try { int limit = Config.PoolSize - _channelList.Count; // If the pool is empty, lets obtain a lock and do a full refill if (_channelList.Count == 0) { if (withLock) { if (!Monitor.TryEnter(_repopulateLock, Constants.LOCK_ATTEMPT_PERIOD)) { throw new Exception(Constants.EXCEPTION_CANNOT_OBTAIN_LOCK_REFILL); } inSync = true; } limit = Config.PoolSize - _channelList.Count; } DebugMessage(string.Format("Number of Channels to RefillPool with: {0}", limit)); for (int loop = 0; loop < limit; loop++) { if (_channelList.Count <= Config.PoolSize) // This is just a safeguard. { //TChannel chann = _channelFactory.CreateChannel(); TChannel chann = ChannelFactory.CreateChannel(); if (chann == null) { throw new Exception(Constants.EXCEPTION_CANNOT_CREATE_CHANNEL); } chanContext = new ChannelContext <TChannel>(chann); try { ((ICommunicationObject)chann).Faulted += new EventHandler(ChannelPool_Faulted); ((IChannel)chann).Open(); _channelList.Add(chanContext); } catch (CommunicationException ce) { // Typically, the initiation of the secure conversation has failed at this point as the server cannot process any more pending // Secure conversations requirests. string msg = string.Format("Error opening a channel to add to the pool. [{0}\n{1}]", ce.Message, ce.InnerException != null ? ce.InnerException.Message : ""); DebugMessage(msg); throw; //break; } } // If we didn't get a lock in the first place when adding in some proxies, and suddenly load increased and exhausted our pool // then we check here if (_channelList.Count == 0) { DebugMessage("Attempting secondary lock in refill..."); if (withLock) { if (!Monitor.TryEnter(_repopulateLock, Constants.LOCK_ATTEMPT_PERIOD)) { throw new Exception("Canot get lock for refill!"); } inSync = true; } } } } finally { if (inSync && withLock) { Monitor.Exit(_repopulateLock); } } }