def _run_task(self, key, version, task_class, module_search_path, \ worker_key, args={}, workunits=None, main_worker=None, task_id=None): """ Runs a task on this node. The worker scheduler on master makes all decisions about which worker to run on. This method only checks to see if the worker is already running or not. This is a very explicit and deliberate division of repsonsibility. Allowing decisions here dilutes the ability of the Master to control the cluster @param key - task key @param version - version of task to run @param task_class - task class to be created TODO why is this here? @param module_search_path - TODO why is this here? @param worker_key - key of worker to run task on @param args - args for task @param subtask_key - key of subtask to run @param workunit_key - key of workunit to run @param main_worker - main worker for this task @param task_id - id of task being run """ logger.info('RunTask:%s key=%s sub=%s main=%s' \ % (task_id, key, workunits, main_worker)) worker = None with self.__lock: if worker_key in self.workers: # worker exists. reuse it. logger.debug('RunTask - Using existing worker %s' % worker_key) worker = self.workers[worker_key] worker.run_task_deferred = worker.remote.callRemote('run_task',\ key, version, args, workunits, main_worker, task_id) else: # worker not running. start it saving the information required # to start the subtask. This function will return a deferred # to the master. The deferred will be logger.debug('RunTask - Spawning worker: %s', worker_key) worker = WorkerAvatar(self.worker_connection_manager, \ worker_key) worker.worker_key = worker_key worker.run_task_deferred = Deferred() pydra_root = pydra.__file__[:pydra.__file__.rfind('/')] try: worker.popen = Popen(['python', '%s/cluster/worker/worker.py' % pydra_root, worker_key, pydra_settings.WORKER_PORT.__str__()]) except OSError: # XXX ocassionally processes will have a communcation error # while loading. The process will be running but the POpen # object is not constructed. This means that we have no # access to the subprocess functions. Instead we must get # the pid from the newly run process after it starts. The # pid can then be used instead of the Popen object. # # relevant bugs: # http://pydra-project.osuosl.org/ticket/158 # http://bugs.python.org/issue1068268 debug.warn('OSError while spawning process, failing back to pid. see ticket #158') worker.run_task_deferred.addCallback(worker.get_pid) self.workers[worker_key] = worker worker.key = key worker.version = version worker.args = args worker.main_worker = main_worker worker.task_id=task_id if worker_key == main_worker: worker.local_workunits = workunits else: worker.workunits = workunits return worker.run_task_deferred