void connect(object obj) { ConnectionThread cxn = (ConnectionThread)obj; try { cxn.Connection.connect(); // Authenticated Vista Connection Handling if (this.PoolSource.Credentials != null) // should be an authenticated connection! { AbstractPermission permission = new MenuOption(VistaConstants.CAPRI_CONTEXT); permission.IsPrimary = true; if (String.IsNullOrEmpty(this.PoolSource.Credentials.AccountName) || String.IsNullOrEmpty(this.PoolSource.Credentials.AccountPassword)) { cxn.Connection.Account.AuthenticationMethod = VistaConstants.NON_BSE_CREDENTIALS; // if no A/V codes, visit } else { cxn.Connection.Account.AuthenticationMethod = VistaConstants.LOGIN_CREDENTIALS; } cxn.Connection.Account.authenticateAndAuthorize(this.PoolSource.Credentials, permission); } // END Authenticated cxn handling else if (cxn.Connection is VistaPoolConnection) // else if pool cxn and no creds - get default state { ((VistaPoolConnection)cxn.Connection)._rawConnectionSymbolTable = ((VistaPoolConnection)cxn.Connection).getState(); } this.TotalResources++; cxn.Connection.setTimeout(this.PoolSource.Timeout); // now gracefully timing out connections! } catch (Exception) { cxn.Connection.IsConnected = false; } }
void connect(object obj) { ConnectionThread cxn = (ConnectionThread)obj; try { cxn.Connection.connect(); // Authenticated Vista Connection Handling if (this.PoolSource.Credentials != null) // should be an authenticated connection! { if (this.PoolSource.Permission == null) { this.PoolSource.Permission = new MenuOption(VistaConstants.CAPRI_CONTEXT); } this.PoolSource.Permission.IsPrimary = true; if (String.IsNullOrEmpty(this.PoolSource.Credentials.AccountName) || String.IsNullOrEmpty(this.PoolSource.Credentials.AccountPassword)) { cxn.Connection.Account.AuthenticationMethod = VistaConstants.NON_BSE_CREDENTIALS; // if no A/V codes, visit } else { cxn.Connection.Account.AuthenticationMethod = VistaConstants.LOGIN_CREDENTIALS; } cxn.Connection.Account.authenticateAndAuthorize(this.PoolSource.Credentials, this.PoolSource.Permission); } // END Authenticated cxn handling else if (cxn.Connection is VistaPoolConnection) // else if pool cxn and no creds - get default state { ((VistaPoolConnection)cxn.Connection)._rawConnectionSymbolTable = ((VistaPoolConnection)cxn.Connection).getState(); } //this.incrementResourceCount(); _lastSuccessfulCxn = DateTime.Now; _consecutiveCxnErrorCount = 0; // System.Console.WriteLine(String.Format("Successfully added a connection - total resources {0}", this.TotalResources)); //this.TotalResources++; cxn.Connection.setTimeout(this.PoolSource.Timeout); // now gracefully timing out connections! } catch (Exception exc) { _consecutiveCxnErrorCount++; //LogUtils.getInstance().Log("There was a problem connecting to " + ((ConnectionPoolSource)this.PoolSource).CxnSource.SiteId.Id + ": " + exc.Message); cxn.Connection.IsConnected = false; disconnect(cxn.Connection); } }
void growPool() { if (_consecutiveCxnErrorCount > this.PoolSource.MaxConsecutiveErrors) // we want to recognize when a site might be down, network issues, etc. - wait to retry if we have many connection failures without success { if (DateTime.Now.Subtract(_lastSuccessfulCxn).CompareTo(this.PoolSource.WaitOnMaxConsecutiveErrors) < 0) { // LogUtils.getInstance().Log(String.Format("{0} consecutive failed connection attempts... waiting {1} to start new cxns", _consecutiveCxnErrorCount, this.PoolSource.WaitOnMaxConsecutiveErrors.Subtract(DateTime.Now.Subtract(_lastSuccessfulCxn)))); return; // don't start any new cxns if we've seen a lot of errors and haven't waited at least 5 mins (or configurable timespan) } else // waited configured time, reset error vars so growPool will try creating cxns { //LogUtils.getInstance().Log("Resetting error related vars so will re-try instantiating cxns.. " + ((ConnectionPoolSource)this.PoolSource).CxnSource.SiteId.Id); _consecutiveCxnErrorCount = 0; _lastSuccessfulCxn = DateTime.Now; } } if ((_cleanupTasks.Count + this.TotalResources) >= this.PoolSource.MaxPoolSize) { //LogUtils.getInstance().Log("The # of cleanup tasks scheduled + the number of current resources exceeds the max pool size - waiting until cleanup tasks are addressed to grow"); return; // too many cleanup tasks scheduled! don't grow the pool until the cxns we've attempted to start have been addressed } // i think there may be a possible race condition here where a cxn may be disconnected during the size int growSize = this.PoolSource.PoolExpansionSize; if ((this.TotalResources + growSize) > this.PoolSource.MaxPoolSize) // if the growth would expand the pool above the max pool size, only grow by the amount allowed { growSize = this.PoolSource.MaxPoolSize - this.TotalResources; } //LogUtils.getInstance().Log(String.Format("Connection pool at min size {0}/{1} - growing by {2}. Current total resources: {3} - site: {4}", this.PoolSource.MinPoolSize, this.PoolSource.MaxPoolSize, growSize, this.TotalResources, ((ConnectionPoolSource)this.PoolSource).CxnSource.SiteId.Id)); for (int i = 0; i < growSize; i++) { ConnectionThread a = new ConnectionThread(); _startedCxns.Add(a); a.Connection = AbstractDaoFactory.getDaoFactory(AbstractDaoFactory.getConstant(((ConnectionPoolSource)this.PoolSource).CxnSource.Protocol)) .getConnection(((ConnectionPoolSource)this.PoolSource).CxnSource); // Task connectTask = new Task(() => connect(a)); // a.Thread = connectTask; // connectTask.Start(); //connect(a); Thread t = new Thread(new ParameterizedThreadStart(connect)); a.Thread = t; t.Start(a); } }
void growPool() { //Console.WriteLine("Connection pool at min size {0} - growing by {1}", this.PoolSource.MinPoolSize, this.PoolSource.PoolExpansionSize); int growSize = this.PoolSource.PoolExpansionSize; if (this.TotalResources + growSize > this.PoolSource.MaxPoolSize) // if the growth would expand the pool above the max pool size, only grow by the amount allowed { growSize = this.PoolSource.MaxPoolSize - this.TotalResources; } for (int i = 0; i < growSize; i++) { ConnectionThread a = new ConnectionThread(); a.Connection = AbstractDaoFactory.getDaoFactory(AbstractDaoFactory.getConstant(((ConnectionPoolSource)this.PoolSource).CxnSource.Protocol)) .getConnection(((ConnectionPoolSource)this.PoolSource).CxnSource); Thread t = new Thread(new ParameterizedThreadStart(connect)); a.Thread = t; t.Start(a); _startedCxns.Add(a); } }
/// <summary> /// The job of the run function is simply to make sure we have connections available in the pool. If the # of /// connections falls below the threshold, the pool expands (up to the limit). The loop also tries to clean /// up any connections that may have failed /// </summary> internal void run() { //System.Console.WriteLine("Run called..."); //LogUtils.getInstance().Log("Run called on pool " + ((ConnectionPoolSource)this.PoolSource).CxnSource.SiteId.Id); lock (_locker) { // System.Console.WriteLine("Run entered..."); _startupTimestamp = DateTime.Now; while (!Convert.ToBoolean(SHUTDOWN_FLAG)) { System.Threading.Thread.Sleep(500); // this small sleep time prevents the thread from consuming 100% of CPU // this first IF statement checks to see if more connections need to be added to the pool if (_pooledCxns.Count < this.PoolSource.MinPoolSize && _startedCxns.Count == 0) // only grow if we haven't started any connections { if (this.TotalResources < this.PoolSource.MaxPoolSize) { growPool(); } } // the second IF checks if this pool has started any connections - most of the time this should be false so we check it before the getEnumerator call if (_startedCxns.Count > 0) { //Console.WriteLine("Found {0} connections that were started", _startedCxns.Count); //LogUtils.getInstance().Log(String.Format("{0} connections were scheduled to be started", _startedCxns.Count)); IEnumerator <ConnectionThread> enumerator = _startedCxns.GetEnumerator(); while (enumerator.MoveNext()) { ConnectionThread current = enumerator.Current; Thread t = current.Thread; //if (current.Connection.IsConnected) if (!(t.IsAlive) && current.Connection.IsConnected) // check if started connection is ready for our pool { try { t.Join(0); } catch (Exception) { } //Console.WriteLine("Found successfully started connection"); this.incrementResourceCount(); _pooledCxns.Add(current.Connection); _cxnsToRemove.Add(current); //LogUtils.getInstance().Log(String.Format("Found a successful connection - incremented resource count to {0} and added to pool containing {1} cxns ({2})", this.TotalResources, this._pooledCxns.Count, ((ConnectionPoolSource)this.PoolSource).CxnSource.SiteId.Id)); } //else if (!current.Connection.IsConnected) // check if started connection thread has completed but for any reason disconnected else if (!(t.IsAlive) && !current.Connection.IsConnected) // check if started connection thread has completed but for any reason disconnected { try { t.Join(0); } catch (Exception) { } // Console.WriteLine("Found apparent failed connection - removing"); //LogUtils.getInstance().Log("It appears one of the started connections failed to connect... " + ((ConnectionPoolSource)this.PoolSource).CxnSource.SiteId.Id); _cxnsToRemove.Add(current); } else if (DateTime.Now.Subtract(current.Timestamp).TotalSeconds > this.PoolSource.WaitTime.TotalSeconds) // lastly check for long running connection attempts { //LogUtils.getInstance().Log("Found long running connection attempt - scheduling for cleanup: " + ((ConnectionPoolSource)this.PoolSource).CxnSource.SiteId.Id); _cxnsToRemove.Add(current); try { // create async task to wait for the thread to stop and disconnect the cxn just to be sure things are cleaned up Task disconnectTask = new System.Threading.Tasks.Task(() => { t.Join(this.PoolSource.WaitTime); // should be enough - waiting for double pool wait time in total disconnect(current.Connection); }); _cleanupTasks.Add(disconnectTask); disconnectTask.Start(); } catch (AggregateException ae) { /*LogUtils.getInstance().Log(ae.ToString()); */ } catch (Exception) { /* swallow */ } } } } // per previous IF - can't modify collection while enumerating so the removal of failed connections is a separate step if (_cxnsToRemove.Count > 0) { foreach (ConnectionThread t in _cxnsToRemove) { _startedCxns.Remove(t); } _cxnsToRemove = new List <ConnectionThread>(); } try { checkCleanupTasks(); } catch (Exception) { } } } // LogUtils.getInstance().Log("Run exited for pool " + ((ConnectionPoolSource)this.PoolSource).CxnSource.SiteId.Id); }
/// <summary> /// The job of the run function is simply to make sure we have connections available in the pool. If the # of /// connections falls below the threshold, the pool expands (up to the limit). The loop also tries to clean /// up any connections that may have failed /// </summary> internal void run() { lock (_locker) { _startupTimestamp = DateTime.Now; while (!Convert.ToBoolean(SHUTDOWN_FLAG)) { System.Threading.Thread.Sleep(100); // this small sleep time prevents the thread from consuming 100% of CPU // this first IF statement checks to see if more connections need to be added to the pool if (_pooledCxns.Count < this.PoolSource.MinPoolSize && _startedCxns.Count == 0) // only grow if we haven't started any connections { if (this.TotalResources < this.PoolSource.MaxPoolSize) { growPool(); } } // the second IF checks if this pool has started any connections - most of the time this should be false so we check it before the getEnumerator call if (_startedCxns.Count > 0) { //Console.WriteLine("Found {0} connections that were started", _startedCxns.Count); IEnumerator <ConnectionThread> enumerator = _startedCxns.GetEnumerator(); while (enumerator.MoveNext()) { ConnectionThread current = enumerator.Current; Thread t = current.Thread; if (t.ThreadState != ThreadState.Running && current.Connection.IsConnected) // check if started connection is ready for our pool { //Console.WriteLine("Found successfully started connection"); _pooledCxns.Add(current.Connection); _cxnsToRemove.Add(current); } else if (t.ThreadState == ThreadState.Stopped && !current.Connection.IsConnected) // check if started connection thread has completed but for any reason disconnected { //Console.WriteLine("Found apparent failed connection - removing"); _cxnsToRemove.Add(current); } else if (DateTime.Now.Subtract(current.Timestamp).TotalSeconds > this.PoolSource.WaitTime.TotalSeconds) // lastly check for long running connection attempts { //Console.WriteLine("Found long running connection attempt - aborting"); try { // don't really want to do this - could bubble up uncaught and bring down the process... should we just add the cxn to the remove list? current.Thread.Abort(); } catch (Exception) { } finally { _cxnsToRemove.Add(current); } } } } // per previous IF - can't modify collection while enumerating so the removal of failed connections is a separate step if (_cxnsToRemove.Count > 0) { foreach (ConnectionThread t in _cxnsToRemove) { _startedCxns.Remove(t); } _cxnsToRemove = new List <ConnectionThread>(); } } } }