def status_report( self, company_id: str, user_id: str, ip: str, report: StatusReportRequest ) -> None: """ Write worker status report :param company_id: worker's company ID :param user_id: user_id ID under which this worker is running :raise bad_request.InvalidTaskId: the reported task was not found :return: worker entry instance """ entry = self._get_worker(company_id, user_id, report.worker) try: entry.ip = ip now = datetime.utcnow() entry.last_activity_time = now if report.machine_stats: self._log_stats_to_es( company_id=company_id, company_name=entry.company.name, worker=report.worker, timestamp=report.timestamp, task=report.task, machine_stats=report.machine_stats, ) entry.queue = report.queue if report.queues: entry.queues = report.queues if not report.task: entry.task = None else: with translate_errors_context(): query = dict(id=report.task, company=company_id) update = dict( last_worker=report.worker, last_worker_report=now, last_update=now, ) # modify(new=True, ...) returns the modified object task = Task.objects(**query).modify(new=True, **update) if not task: raise bad_request.InvalidTaskId(**query) entry.task = IdNameEntry(id=task.id, name=task.name) entry.last_report_time = now except APIError: raise except Exception as e: msg = "Failed processing worker status report" log.exception(msg) raise server_error.DataError(msg, err=e.args[0]) finally: self._save_worker(entry)
def _get_worker(self, company_id: str, user_id: str, worker: str) -> WorkerEntry: """ Get a worker entry for the provided worker ID. The entry is loaded from Redis if it exists (i.e. worker has already been registered), otherwise the worker is registered and its entry stored into Redis). :param company_id: worker's company ID :param user_id: user ID under which this worker is running :param worker: worker ID :raise bad_request.InvalidWorkerId: in case the worker id was not found :return: worker entry instance """ key = self._get_worker_key(company_id, user_id, worker) with TimingContext("redis", "get_worker"): data = self.redis.get(key) if data: try: entry = WorkerEntry.from_json(data) if not entry.key: entry.key = key self._save_worker(entry) return entry except Exception as e: msg = "Failed parsing worker entry" log.exception(msg) raise server_error.DataError(msg, err=e.args[0]) # Failed loading worker from Redis if config.get("apiserver.workers.auto_register", False): try: return self.register_worker(company_id, user_id, worker) except Exception: log.error( "Failed auto registration of {} for company {}".format( worker, company_id ) ) raise bad_request.InvalidWorkerId(worker=worker)
def get_all( self, company_id: str, last_seen: Optional[int] = None ) -> Sequence[WorkerEntry]: """ Get all the company workers that were active during the last_seen period :param company_id: worker's company id :param last_seen: period in seconds to check. Min value is 1 second :return: """ try: workers = self._get(company_id) except Exception as e: raise server_error.DataError("failed loading worker entries", err=e.args[0]) if last_seen: ref_time = datetime.utcnow() - timedelta(seconds=max(1, last_seen)) workers = [ w for w in workers if w.last_activity_time.replace(tzinfo=None) >= ref_time ] return workers