def testAddComponent(self): """ _testAddComponent_ Test creation of components and worker threads as well as the get heartbeat DAOs """ comp1 = HeartbeatAPI("testComponent1", pollInterval=60, heartbeatTimeout=600) comp1.registerComponent() self.assertEqual(comp1.getHeartbeatInfo(), []) # no worker thread yet comp1.registerWorker("testWorker1") self.assertEqual(len(comp1.getHeartbeatInfo()), 1) comp1.registerWorker("testWorker2") self.assertEqual(len(comp1.getHeartbeatInfo()), 2) comp2 = HeartbeatAPI("testComponent2", pollInterval=30, heartbeatTimeout=300) comp2.registerComponent() self.assertEqual(comp2.getHeartbeatInfo(), []) # no worker thread yet self.assertEqual(len(comp2.getAllHeartbeatInfo()), 2) comp2.registerWorker("testWorker21") self.assertEqual(len(comp2.getHeartbeatInfo()), 1) self.assertEqual(len(comp2.getAllHeartbeatInfo()), 3) comp1.updateWorkerHeartbeat("testWorker1", "Running") comp1.updateWorkerHeartbeat("testWorker2", "Running") comp2.updateWorkerHeartbeat("testWorker21", "Running") self.assertEqual(len(comp1.getAllHeartbeatInfo()), 3) self.assertEqual(len(comp2.getAllHeartbeatInfo()), 3) comp1Res = comp1.getHeartbeatInfo() comp2Res = comp2.getHeartbeatInfo() self.assertEqual(len(comp1Res), 2) self.assertEqual(len(comp2Res), 1) self.assertItemsEqual([item["name"] for item in comp1Res], ["testComponent1", "testComponent1"]) self.assertItemsEqual([item["worker_name"] for item in comp1Res], ["testWorker1", "testWorker2"]) self.assertItemsEqual([item["state"] for item in comp1Res], ["Running", "Running"]) self.assertItemsEqual([item["poll_interval"] for item in comp1Res], [60, 60]) self.assertItemsEqual([item["update_threshold"] for item in comp1Res], [600, 600]) self.assertItemsEqual([item["name"] for item in comp2Res], ["testComponent2"]) self.assertItemsEqual([item["worker_name"] for item in comp2Res], ["testWorker21"]) self.assertItemsEqual([item["state"] for item in comp2Res], ["Running"]) self.assertItemsEqual([item["poll_interval"] for item in comp2Res], [30]) self.assertItemsEqual([item["update_threshold"] for item in comp2Res], [300])
def testHeartbeat(self): testComponent = HeartbeatAPI("testComponent") testComponent.registerComponent() self.assertEqual(testComponent.getHeartbeatInfo(), []) testComponent.updateWorkerHeartbeat("testWorker") result = testComponent.getHeartbeatInfo() self.assertEqual(len(result), 1) self.assertEqual(result[0]['worker_name'], "testWorker") time.sleep(1) testComponent.updateWorkerHeartbeat("testWorker2") result = testComponent.getHeartbeatInfo() self.assertEqual(len(result), 1) self.assertEqual(result[0]['worker_name'], "testWorker2") time.sleep(1) testComponent.updateWorkerHeartbeat("testWorker") result = testComponent.getHeartbeatInfo() self.assertEqual(len(result), 1) self.assertEqual(result[0]['worker_name'], "testWorker") testComponent = HeartbeatAPI("test2Component") testComponent.registerComponent() time.sleep(1) testComponent.updateWorkerHeartbeat("test2Worker") result = testComponent.getHeartbeatInfo() self.assertEqual(len(result), 2) self.assertEqual(result[0]['worker_name'], "testWorker") self.assertEqual(result[1]['worker_name'], "test2Worker") time.sleep(1) testComponent.updateWorkerHeartbeat("test2Worker2") result = testComponent.getHeartbeatInfo() self.assertEqual(len(result), 2) self.assertEqual(result[0]['worker_name'], "testWorker") self.assertEqual(result[1]['worker_name'], "test2Worker2") time.sleep(1) testComponent.updateWorkerHeartbeat("test2Worker") result = testComponent.getHeartbeatInfo() self.assertEqual(len(result), 2) self.assertEqual(result[0]['worker_name'], "testWorker") self.assertEqual(result[1]['worker_name'], "test2Worker") testComponent.updateWorkerError("test2Worker", "Error1") result = testComponent.getHeartbeatInfo() self.assertEqual(result[1]['error_message'], "Error1")
def testHeartbeat(self): testComponent = HeartbeatAPI("testComponent") testComponent.pollInterval = 10 testComponent.registerComponent() self.assertEqual(testComponent.getHeartbeatInfo(), []) testComponent.updateWorkerHeartbeat("testWorker") result = testComponent.getHeartbeatInfo() self.assertEqual(len(result), 1) self.assertEqual(result[0]['worker_name'], "testWorker") time.sleep(1) testComponent.updateWorkerHeartbeat("testWorker2") result = testComponent.getHeartbeatInfo() self.assertEqual(len(result), 1) self.assertEqual(result[0]['worker_name'], "testWorker2") time.sleep(1) testComponent.updateWorkerHeartbeat("testWorker") result = testComponent.getHeartbeatInfo() self.assertEqual(len(result), 1) self.assertEqual(result[0]['worker_name'], "testWorker") testComponent = HeartbeatAPI("test2Component") testComponent.pollInterval = 20 testComponent.registerComponent() time.sleep(1) testComponent.updateWorkerHeartbeat("test2Worker") result = testComponent.getHeartbeatInfo() self.assertEqual(len(result), 2) self.assertEqual(result[0]['worker_name'], "testWorker") self.assertEqual(result[1]['worker_name'], "test2Worker") time.sleep(1) testComponent.updateWorkerHeartbeat("test2Worker2") result = testComponent.getHeartbeatInfo() self.assertEqual(len(result), 2) self.assertEqual(result[0]['worker_name'], "testWorker") self.assertEqual(result[1]['worker_name'], "test2Worker2") time.sleep(1) testComponent.updateWorkerHeartbeat("test2Worker") result = testComponent.getHeartbeatInfo() self.assertEqual(len(result), 2) self.assertEqual(result[0]['worker_name'], "testWorker") self.assertEqual(result[1]['worker_name'], "test2Worker") testComponent.updateWorkerError("test2Worker", "Error1") result = testComponent.getHeartbeatInfo() self.assertEqual(result[1]['error_message'], "Error1")
def testAddComponent(self): """ _testAddComponent_ Test creation of components and worker threads as well as the get heartbeat DAOs """ comp1 = HeartbeatAPI("testComponent1", pollInterval=60, heartbeatTimeout=600) comp1.registerComponent() self.assertEqual(comp1.getHeartbeatInfo(), []) # no worker thread yet comp1.registerWorker("testWorker1") self.assertEqual(len(comp1.getHeartbeatInfo()), 1) comp1.registerWorker("testWorker2") self.assertEqual(len(comp1.getHeartbeatInfo()), 2) comp2 = HeartbeatAPI("testComponent2", pollInterval=30, heartbeatTimeout=300) comp2.registerComponent() self.assertEqual(comp2.getHeartbeatInfo(), []) # no worker thread yet self.assertEqual(len(comp2.getAllHeartbeatInfo()), 2) comp2.registerWorker("testWorker21") self.assertEqual(len(comp2.getHeartbeatInfo()), 1) self.assertEqual(len(comp2.getAllHeartbeatInfo()), 3) comp1.updateWorkerHeartbeat("testWorker1", "Running") comp1.updateWorkerHeartbeat("testWorker2", "Running") comp2.updateWorkerHeartbeat("testWorker21", "Running") self.assertEqual(len(comp1.getAllHeartbeatInfo()), 3) self.assertEqual(len(comp2.getAllHeartbeatInfo()), 3) comp1Res = comp1.getHeartbeatInfo() comp2Res = comp2.getHeartbeatInfo() self.assertEqual(len(comp1Res), 2) self.assertEqual(len(comp2Res), 1) self.assertItemsEqual([item["name"] for item in comp1Res], ["testComponent1", "testComponent1"]) self.assertItemsEqual([item["worker_name"] for item in comp1Res], ["testWorker1", "testWorker2"]) self.assertItemsEqual([item["state"] for item in comp1Res], ["Running", "Running"]) self.assertItemsEqual([item["poll_interval"] for item in comp1Res], [60, 60]) self.assertItemsEqual([item["update_threshold"] for item in comp1Res], [600, 600]) self.assertItemsEqual([item["name"] for item in comp2Res], ["testComponent2"]) self.assertItemsEqual([item["worker_name"] for item in comp2Res], ["testWorker21"]) self.assertItemsEqual([item["state"] for item in comp2Res], ["Running"]) self.assertItemsEqual([item["poll_interval"] for item in comp2Res], [30]) self.assertItemsEqual([item["update_threshold"] for item in comp2Res], [300])
class ProcessPool: def __init__(self, slaveClassName, totalSlaves, componentDir, config, slaveInit = None, namespace = None): """ __init__ Constructor for the process pool. The slave class name must be based inside the WMComponent namespace. For examples, the JobAccountant would pass in 'JobAccountant.AccountantWorker' to run the AccountantWorker class. All log files will be stored in the component directory that is passed in. Each slave will have its own log file. Note that the config is only used to determine database connection parameters. It is not passed to the slave class. The slaveInit parameter will be serialized and passed to the slave class's constructor. """ self.enqueueIndex = 0 self.dequeueIndex = 0 self.runningWork = 0 #Use the Services.Requests JSONizer, which handles __to_json__ calls self.jsonHandler = JSONRequests() # heartbeat should be registered at this point if getattr(config.Agent, "useHeartbeat", True): self.heartbeatAPI = HeartbeatAPI(getattr(config.Agent, "componentName", "ProcPoolSlave")) self.slaveClassName = slaveClassName self.componentDir = componentDir self.config = config # Grab the python version from the current version # Assume naming convention pythonA.B, i.e., python2.4 for v2.4.X majorVersion = sys.version_info[0] minorVersion = sys.version_info[1] if majorVersion and minorVersion: self.versionString = "python%i.%i" % (majorVersion, minorVersion) else: self.versionString = "python2.4" self.workers = [] self.nSlaves = totalSlaves self.slaveInit = slaveInit self.namespace = namespace # Now actually create the slaves self.createSlaves() return def createSlaves(self): """ _createSlaves_ Create the slaves by using the values from __init__() Moving it into a separate function allows us to restart all of them. """ totalSlaves = self.nSlaves slaveClassName = self.slaveClassName config = self.config slaveInit = self.slaveInit namespace = self.namespace slaveArgs = [self.versionString, __file__, self.slaveClassName] if hasattr(config.CoreDatabase, "socket"): socket = config.CoreDatabase.socket else: socket = None (connectDialect, junk) = config.CoreDatabase.connectUrl.split(":", 1) if connectDialect.lower() == "mysql": dialect = "MySQL" elif connectDialect.lower() == "oracle": dialect = "Oracle" elif connectDialect.lower() == "sqlite": dialect = "SQLite" dbConfig = {"dialect": dialect, "connectUrl": config.CoreDatabase.connectUrl, "socket": socket, "componentDir": self.componentDir} if namespace: # Then add a namespace to the config dbConfig['namespace'] = namespace encodedDBConfig = self.jsonHandler.encode(dbConfig) if slaveInit == None: encodedSlaveInit = None else: encodedSlaveInit = self.jsonHandler.encode(slaveInit) count = 0 while totalSlaves > 0: #For each worker you want create a slave process #That process calls this code (WMCore.ProcessPool) and opens #A process pool that loads the designated class slaveProcess = subprocess.Popen(slaveArgs, stdin = subprocess.PIPE, stdout = subprocess.PIPE) slaveProcess.stdin.write("%s\n" % encodedDBConfig) if encodedSlaveInit == None: slaveProcess.stdin.write("\n") else: slaveProcess.stdin.write("%s\n" % encodedSlaveInit) slaveProcess.stdin.flush() self.workers.append(WorkerProcess(subproc = slaveProcess)) workerName = self._subProcessName(self.slaveClassName, count) if getattr(self.config.Agent, "useHeartbeat", True): self.heartbeatAPI.updateWorkerHeartbeat(workerName, pid = slaveProcess.pid) totalSlaves -= 1 count += 1 return def _subProcessName(self, slaveClassName, sequence): """ subProcessName for heartbeat could change to use process ID as a suffix """ return "%s_%s" % (slaveClassName, sequence + 1) def __del__(self): """ __del__ Kill all the workers processes by sending them an invalid JSON object. This will cause them to shut down. """ for worker in self.workers: try: worker.delete() except Exception, ex: pass self.workers = [] return