Example #1
0
 void TimedREConnectionMonitor_SkippedFreeingConnection(string reasonSkipped, FreeingEventArgs e)
 {
     logBuffer.AppendFormat("Skipped - {0}\n", reasonSkipped);
 }
Example #2
0
 void TimedREConnectionMonitor_FreeingConnection(FreeingEventArgs e)
 {
 }
Example #3
0
        // Base implementation
        public virtual IEnumerable <FilteredLockConnection> FreeConnections(bool debug)
        {
            try
            {
                // Connect to the database using the connection string specified in the app settings
                var connectionString = Settings[MonitorSettings.DBConnectionString];

                if (ConnectingToDatabase != null)
                {
                    ConnectingToDatabase(ref connectionString);
                }

                var db = new Parise.RaisersEdge.ConnectionMonitor.Data.RecmDataContext(connectionString);
                db.Log = Console.Out;

                if (ConnectedToDatabase != null)
                {
                    ConnectedToDatabase(db);
                }

                #region Dead Connection Lock Clean Up (RE Stored Procedure)

                // Clean up dead connection locks - very important
                // Affects the dbo.LOCKCONNECTIONS table

                if (CleaningUpDeadLocks != null)
                {
                    CleaningUpDeadLocks(db);
                }

                var spResult = db.CleanupDeadConnectionLocks();

                if (CleanedUpDeadLocks != null)
                {
                    CleanedUpDeadLocks(spResult);
                }

                #endregion

                // Retrieve entire connection list from DB and order by idle time
                // ToList() forces LINQ to retrieve data from the server
                //StatusMessage(db.GetCommand(db.LockConnections_AllActiveREConnections_ClientOnly.AsQueryable()).CommandText);

                var connectionList = db.LockConnections_AllActiveREConnections_ClientOnly.OrderByDescending(a => a.REProcess.IdleTime.TotalMilliseconds);

                // Get licenses in use (Distinct RE User Names)
                var inUse = connectionList.Select(l => l.Lock.User).Distinct().Count();

                var totalLicenseCount = int.Parse(Settings[MonitorSettings.NumLicenses]);
                var leastMinutesIdle  = double.Parse(Settings[MonitorSettings.LeastMinutesIdle]);

                if (StatusMessage != null)
                {
                    StatusMessage(string.Format("{0}/{1} licenses in use.", inUse, totalLicenseCount));
                }

                if (inUse >= totalLicenseCount)
                {
                    // Get exclusion list
                    var excludedHosts   = Settings[MonitorSettings.ExcludedHosts].ToLower();
                    var excludedREUsers = Settings[MonitorSettings.ExcludedREUsers].ToLower();

                    // Get candidates that are over the idle limit and not excluded
                    var bootCandidates = connectionList.Where(a =>
                                                              !excludedREUsers.Contains(a.Lock.User.Name.ToLower()) &&
                                                              !excludedHosts.Contains(a.Lock.MachineName.Split(':')[0].ToLower()) &&
                                                              a.AllProcesses.First().IdleTime.TotalMinutes >= leastMinutesIdle);

                    // Take enough to free one license - this ensures proper freeing if the service is restarted
                    var bootList = bootCandidates.Take(inUse - totalLicenseCount + 1);

                    if (StatusMessage != null)
                    {
                        StatusMessage(string.Format("Attempting to free {0} license(s).\n\nBooting {1} of {2} candidates.\n\n", inUse - totalLicenseCount + 1, bootCandidates.Count(), bootList.Count()));
                    }

                    var actualBootList = new List <FilteredLockConnection> {
                    };

                    foreach (var connection in bootList)
                    {
                        if (FreeingLock != null)
                        {
                            FreeingLock(connection);
                        }

                        // Refresh the current status of the process and related items
                        var freshProcess = connection.REProcess;
                        try
                        {
                            db.Refresh(RefreshMode.OverwriteCurrentValues, connection.REProcess);
                            // We only want to kill sleeping processes!!!
                            var sleepingCount = freshProcess.RelatedProcesses.Where(p => p.status.Trim().Equals("sleeping", StringComparison.CurrentCultureIgnoreCase)).Count();
                            if (sleepingCount == freshProcess.RelatedProcesses.Count)
                            {
                                //loggableEntry += connection.Lock.MachineName + " -- " + connection.Lock.User.Name + " -- " + connection.REProcess.hostname + "\n";
                                //"\tIssued kill " + process.spid + " -- " + process.program_name.Trim() + " -- " + process.status.Trim() + " -- " + process.IdleTimeFormatted("{h:D2}:{m:D2}:{s:D2}:{ms:D2}\n");
                                foreach (var process in freshProcess.RelatedProcesses)
                                {
                                    var  killResult = 99;
                                    bool killIt     = true;

                                    if (FreeingConnection != null)
                                    {
                                        var args = new FreeingEventArgs(connection, process);
                                        FreeingConnection(args);
                                        killIt = !args.Cancel;
                                    }

                                    if (killIt)
                                    {
                                        // This will kill the SQL process
                                        if (!debug)
                                        {
                                            killResult = db.Kill(process);
                                        }

                                        if (FreedConnection != null)
                                        {
                                            FreedConnection(new FreedEventArgs(connection, process, killResult));
                                        }
                                    }
                                }

                                actualBootList.Add(connection);
                            }
                            else
                            {
                                if (SkippedFreeingConnection != null)
                                {
                                    SkippedFreeingConnection("Some related processes are active.", new FreeingEventArgs(connection, connection.REProcess));
                                }
                            }
                        }
                        catch (Exception err)
                        {
                            if (GenericError != null)
                            {
                                GenericError(new ErrorEventArgs <Exception>(err));
                            }
                        }
                    }

                    db.Dispose();
                    return(actualBootList);
                }
                else
                {
                    db.Dispose();
                    return(new List <FilteredLockConnection> {
                    });
                }
            }
            catch (Exception err)
            {
                if (GenericError != null)
                {
                    GenericError(new ErrorEventArgs <Exception>(err));
                }

                return(new List <FilteredLockConnection> {
                });
            }
        }