Merge "Unify the zookeeper/redis jobboard iterators"
This commit is contained in:
		| @@ -753,9 +753,11 @@ return cmsgpack.pack(result) | ||||
|         while True: | ||||
|             jc = self.job_count | ||||
|             if jc > 0: | ||||
|                 it = self.iterjobs() | ||||
|                 return it | ||||
|             else: | ||||
|                 curr_jobs = self._fetch_jobs() | ||||
|                 if curr_jobs: | ||||
|                     return base.JobBoardIterator( | ||||
|                         self, LOG, | ||||
|                         board_fetch_func=lambda ensure_fresh: curr_jobs) | ||||
|             if w.expired(): | ||||
|                 raise exc.NotFound("Expired waiting for jobs to" | ||||
|                                    " arrive; waited %s seconds" | ||||
| @@ -768,7 +770,7 @@ return cmsgpack.pack(result) | ||||
|                     delay = min(delay * 2, max_delay) | ||||
|                 sleep_func(delay) | ||||
|  | ||||
|     def iterjobs(self, only_unclaimed=False, ensure_fresh=False): | ||||
|     def _fetch_jobs(self): | ||||
|         with _translate_failures(): | ||||
|             raw_postings = self._client.hgetall(self.listings_key) | ||||
|         postings = [] | ||||
| @@ -782,13 +784,13 @@ return cmsgpack.pack(result) | ||||
|                            book_data=posting.get('book'), | ||||
|                            backend=self._persistence) | ||||
|             postings.append(job) | ||||
|         postings = sorted(postings) | ||||
|         for job in postings: | ||||
|             if only_unclaimed: | ||||
|                 if job.state == states.UNCLAIMED: | ||||
|                     yield job | ||||
|             else: | ||||
|                 yield job | ||||
|         return sorted(postings) | ||||
|  | ||||
|     def iterjobs(self, only_unclaimed=False, ensure_fresh=False): | ||||
|         return base.JobBoardIterator( | ||||
|             self, LOG, only_unclaimed=only_unclaimed, | ||||
|             ensure_fresh=ensure_fresh, | ||||
|             board_fetch_func=lambda ensure_fresh: self._fetch_jobs()) | ||||
|  | ||||
|     @base.check_who | ||||
|     def consume(self, job, who): | ||||
|   | ||||
| @@ -14,7 +14,6 @@ | ||||
| #    License for the specific language governing permissions and limitations | ||||
| #    under the License. | ||||
|  | ||||
| import collections | ||||
| import contextlib | ||||
| import functools | ||||
| import sys | ||||
| @@ -180,74 +179,6 @@ class ZookeeperJob(base.Job): | ||||
|         return hash(self.path) | ||||
|  | ||||
|  | ||||
| class ZookeeperJobBoardIterator(six.Iterator): | ||||
|     """Iterator over a zookeeper jobboard that iterates over potential jobs. | ||||
|  | ||||
|     It supports the following attributes/constructor arguments: | ||||
|  | ||||
|     * ``ensure_fresh``: boolean that requests that during every fetch of a new | ||||
|       set of jobs this will cause the iterator to force the backend to | ||||
|       refresh (ensuring that the jobboard has the most recent job listings). | ||||
|     * ``only_unclaimed``: boolean that indicates whether to only iterate | ||||
|       over unclaimed jobs. | ||||
|     """ | ||||
|  | ||||
|     _UNCLAIMED_JOB_STATES = ( | ||||
|         states.UNCLAIMED, | ||||
|     ) | ||||
|  | ||||
|     _JOB_STATES = ( | ||||
|         states.UNCLAIMED, | ||||
|         states.COMPLETE, | ||||
|         states.CLAIMED, | ||||
|     ) | ||||
|  | ||||
|     def __init__(self, board, only_unclaimed=False, ensure_fresh=False): | ||||
|         self._board = board | ||||
|         self._jobs = collections.deque() | ||||
|         self._fetched = False | ||||
|         self.ensure_fresh = ensure_fresh | ||||
|         self.only_unclaimed = only_unclaimed | ||||
|  | ||||
|     @property | ||||
|     def board(self): | ||||
|         """The board this iterator was created from.""" | ||||
|         return self._board | ||||
|  | ||||
|     def __iter__(self): | ||||
|         return self | ||||
|  | ||||
|     def _next_job(self): | ||||
|         if self.only_unclaimed: | ||||
|             allowed_states = self._UNCLAIMED_JOB_STATES | ||||
|         else: | ||||
|             allowed_states = self._JOB_STATES | ||||
|         job = None | ||||
|         while self._jobs and job is None: | ||||
|             maybe_job = self._jobs.popleft() | ||||
|             try: | ||||
|                 if maybe_job.state in allowed_states: | ||||
|                     job = maybe_job | ||||
|             except excp.JobFailure: | ||||
|                 LOG.warn("Failed determining the state of job: %s (%s)", | ||||
|                          maybe_job.uuid, maybe_job.path, exc_info=True) | ||||
|             except excp.NotFound: | ||||
|                 self._board._remove_job(maybe_job.path) | ||||
|         return job | ||||
|  | ||||
|     def __next__(self): | ||||
|         if not self._jobs: | ||||
|             if not self._fetched: | ||||
|                 jobs = self._board._fetch_jobs(ensure_fresh=self.ensure_fresh) | ||||
|                 self._jobs.extend(jobs) | ||||
|                 self._fetched = True | ||||
|         job = self._next_job() | ||||
|         if job is None: | ||||
|             raise StopIteration | ||||
|         else: | ||||
|             return job | ||||
|  | ||||
|  | ||||
| class ZookeeperJobBoard(base.NotifyingJobBoard): | ||||
|     """A jobboard backed by `zookeeper`_. | ||||
|  | ||||
| @@ -388,9 +319,10 @@ class ZookeeperJobBoard(base.NotifyingJobBoard): | ||||
|             self._on_job_posting(children, delayed=False) | ||||
|  | ||||
|     def iterjobs(self, only_unclaimed=False, ensure_fresh=False): | ||||
|         return ZookeeperJobBoardIterator(self, | ||||
|                                          only_unclaimed=only_unclaimed, | ||||
|                                          ensure_fresh=ensure_fresh) | ||||
|         return base.JobBoardIterator( | ||||
|             self, LOG, only_unclaimed=only_unclaimed, | ||||
|             ensure_fresh=ensure_fresh, board_fetch_func=self._fetch_jobs, | ||||
|             board_removal_func=lambda a_job: self._remove_job(a_job.path)) | ||||
|  | ||||
|     def _remove_job(self, path): | ||||
|         if path not in self._known_jobs: | ||||
| @@ -698,10 +630,12 @@ class ZookeeperJobBoard(base.NotifyingJobBoard): | ||||
|                     # must recalculate the amount of time we really have left. | ||||
|                     self._job_cond.wait(watch.leftover(return_none=True)) | ||||
|                 else: | ||||
|                     it = ZookeeperJobBoardIterator(self) | ||||
|                     it._jobs.extend(self._fetch_jobs()) | ||||
|                     it._fetched = True | ||||
|                     return it | ||||
|                     curr_jobs = self._fetch_jobs() | ||||
|                     fetch_func = lambda ensure_fresh: curr_jobs | ||||
|                     removal_func = lambda a_job: self._remove_job(a_job.path) | ||||
|                     return base.JobBoardIterator( | ||||
|                         self, LOG, board_fetch_func=fetch_func, | ||||
|                         board_removal_func=removal_func) | ||||
|  | ||||
|     @property | ||||
|     def connected(self): | ||||
|   | ||||
| @@ -16,11 +16,14 @@ | ||||
| #    under the License. | ||||
|  | ||||
| import abc | ||||
| import collections | ||||
| import contextlib | ||||
|  | ||||
| from oslo_utils import uuidutils | ||||
| import six | ||||
|  | ||||
| from taskflow import exceptions as excp | ||||
| from taskflow import states | ||||
| from taskflow.types import notifier | ||||
|  | ||||
|  | ||||
| @@ -147,6 +150,76 @@ class Job(object): | ||||
|                                                  self.details) | ||||
|  | ||||
|  | ||||
| class JobBoardIterator(six.Iterator): | ||||
|     """Iterator over a jobboard that iterates over potential jobs. | ||||
|  | ||||
|     It provides the following attributes: | ||||
|  | ||||
|     * ``only_unclaimed``: boolean that indicates whether to only iterate | ||||
|       over unclaimed jobs | ||||
|     * ``ensure_fresh``: boolean that requests that during every fetch of a new | ||||
|       set of jobs this will cause the iterator to force the backend to | ||||
|       refresh (ensuring that the jobboard has the most recent job listings) | ||||
|     * ``board``: the board this iterator was created from | ||||
|     """ | ||||
|  | ||||
|     _UNCLAIMED_JOB_STATES = (states.UNCLAIMED,) | ||||
|     _JOB_STATES = (states.UNCLAIMED, states.COMPLETE, states.CLAIMED) | ||||
|  | ||||
|     def __init__(self, board, logger, | ||||
|                  board_fetch_func=None, board_removal_func=None, | ||||
|                  only_unclaimed=False, ensure_fresh=False): | ||||
|         self._board = board | ||||
|         self._logger = logger | ||||
|         self._board_removal_func = board_removal_func | ||||
|         self._board_fetch_func = board_fetch_func | ||||
|         self._fetched = False | ||||
|         self._jobs = collections.deque() | ||||
|         self.only_unclaimed = only_unclaimed | ||||
|         self.ensure_fresh = ensure_fresh | ||||
|  | ||||
|     @property | ||||
|     def board(self): | ||||
|         """The board this iterator was created from.""" | ||||
|         return self._board | ||||
|  | ||||
|     def __iter__(self): | ||||
|         return self | ||||
|  | ||||
|     def _next_job(self): | ||||
|         if self.only_unclaimed: | ||||
|             allowed_states = self._UNCLAIMED_JOB_STATES | ||||
|         else: | ||||
|             allowed_states = self._JOB_STATES | ||||
|         job = None | ||||
|         while self._jobs and job is None: | ||||
|             maybe_job = self._jobs.popleft() | ||||
|             try: | ||||
|                 if maybe_job.state in allowed_states: | ||||
|                     job = maybe_job | ||||
|             except excp.JobFailure: | ||||
|                 self._logger.warn("Failed determining the state of" | ||||
|                                   " job '%s'", maybe_job, exc_info=True) | ||||
|             except excp.NotFound: | ||||
|                 if self._board_removal_func is not None: | ||||
|                     self._board_removal_func(maybe_job) | ||||
|         return job | ||||
|  | ||||
|     def __next__(self): | ||||
|         if not self._jobs: | ||||
|             if not self._fetched: | ||||
|                 if self._board_fetch_func is not None: | ||||
|                     self._jobs.extend( | ||||
|                         self._board_fetch_func( | ||||
|                             ensure_fresh=self.ensure_fresh)) | ||||
|                 self._fetched = True | ||||
|         job = self._next_job() | ||||
|         if job is None: | ||||
|             raise StopIteration | ||||
|         else: | ||||
|             return job | ||||
|  | ||||
|  | ||||
| @six.add_metaclass(abc.ABCMeta) | ||||
| class JobBoard(object): | ||||
|     """A place where jobs can be posted, reposted, claimed and transferred. | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Jenkins
					Jenkins