/** * Run the maintenance thread. Every REFRESH seconds, re-register this app server as alive in * the cluster. Then check for any cluster entries that are more than EXPIRED seconds old, * indicating a failed app server, and remove that record, that server's sessions, generating * appropriate session events so the other app servers know what's going on. The "then" checks * need not be done each iteration - run them on 1 of n randomly choosen iterations. In a * clustered environment, this also distributes the work over the cluster better. */ public void run() { // wait till things are rolling ComponentManager.waitTillConfigured(); if (M_log.isDebugEnabled()) M_log.debug("run()"); while (!m_maintenanceCheckerStop) { try { final String serverIdInstance = m_serverConfigurationService.getServerIdInstance(); if (M_log.isDebugEnabled()) M_log.debug("checking..."); // if we have been closed, reopen! String statement = clusterServiceSql.getReadServerSql(); Object[] fields = new Object[1]; fields[0] = serverIdInstance; List results = m_sqlService.dbRead(statement, fields, null); if (results.isEmpty()) { M_log.warn( "run(): server has been closed in cluster table, reopened: " + serverIdInstance); statement = clusterServiceSql.getInsertServerSql(); fields[0] = serverIdInstance; boolean ok = m_sqlService.dbWrite(statement, fields); if (!ok) { M_log.warn("start(): dbWrite failed"); } } // update our alive and well status else { // register that this app server is alive and well statement = clusterServiceSql.getUpdateServerSql(); fields[0] = serverIdInstance; boolean ok = m_sqlService.dbWrite(statement, fields); if (!ok) { M_log.warn("run(): dbWrite failed: " + statement); } } // pick a random number, 0..99, to see if we want to do the full ghosting / cleanup // activities now int rand = (int) (Math.random() * 100.0); if (rand < m_ghostingPercent) { // get all expired open app servers not me statement = clusterServiceSql.getListExpiredServers(m_expired); // setup the fields to skip reading me! fields[0] = serverIdInstance; List instances = m_sqlService.dbRead(statement, fields, null); // close any severs found to be expired for (Iterator iInstances = instances.iterator(); iInstances.hasNext(); ) { String serverId = (String) iInstances.next(); // close the server - delete the record statement = clusterServiceSql.getDeleteServerSql(); fields[0] = serverId; boolean ok = m_sqlService.dbWrite(statement, fields); if (!ok) { M_log.warn("run(): dbWrite failed: " + statement); } M_log.warn( "run(): ghost-busting server: " + serverId + " from : " + serverIdInstance); } // Close all sessions left over from deleted servers. int nbrClosed = m_usageSessionService.closeSessionsOnInvalidServers(getServers()); if ((nbrClosed > 0) && M_log.isInfoEnabled()) M_log.info("Closed " + nbrClosed + " orphaned usage session records"); // Delete any orphaned locks from closed or missing sessions. statement = clusterServiceSql.getOrphanedLockSessionsSql(); List sessions = m_sqlService.dbRead(statement); if (sessions.size() > 0) { if (M_log.isInfoEnabled()) M_log.info( "Found " + sessions.size() + " closed or deleted sessions in lock table"); statement = clusterServiceSql.getDeleteLocksSql(); for (Iterator iSessions = sessions.iterator(); iSessions.hasNext(); ) { fields[0] = (String) iSessions.next(); boolean ok = m_sqlService.dbWrite(statement, fields); if (!ok) { M_log.warn("run(): dbWrite failed: " + statement); } } } } } catch (Throwable e) { M_log.warn("exception: ", e); } finally { // clear out any current access bindings m_threadLocalManager.clear(); } // cycle every REFRESH seconds if (!m_maintenanceCheckerStop) { try { Thread.sleep(m_refresh * 1000L); } catch (Exception ignore) { } } } if (M_log.isDebugEnabled()) M_log.debug("done"); }