def _merge_task_status(self, task: IscoutTask): """合并处理子任务状态""" try: # 当前模块为 任务发送管理器,只负责 等待发送的任务及其状态管理。 # 合并子任务状态,并将总任务状态从 等待发送更新为正在执行。 # 只要有一个子任务发送成功,则总任务更新为发送成功 # 若全部子任务发送失败,整个任务才算发送失败, # 貌似这样才能在非实时性的任务状态中没什么错 ## 先看是否还有尚未发送的子任务,有的话先不要乱动。。 waitforsendcount: int = self._dbmanager.get_iscoutbtask_count_by_cmdstatus( task._platform, task.taskid, ECommandStatus.WaitForSend) if waitforsendcount > 0: return ## 再看有没有发送成功的,有的话直接总任务发送成功,正在执行 sendsucccount: int = self._dbmanager.get_iscoutbtask_count_by_cmdstatus( task._platform, task.taskid, ECommandStatus.Dealing) if sendsucccount > 0: task.cmdstatus = ECommandStatus.Dealing self._logger.info("IScoutTask all sent, taskid={}".format( task.taskid)) # 只要有一个子任务发送成功,则更新总任务为正在执行(不需要返回回馈数据) if not self._dbmanager.update_iscouttask_status( task._platform, task.taskid, ECommandStatus.Dealing): self._logger.error( "Update IScoutTask cmdstatus to {} faled: taskid:{}". format(ECommandStatus.Dealing.name, task.taskid)) else: task.cmdstatus = ECommandStatus.Failed self._logger.error( "IScoutTask all sent failed, taskid={} objtype={} obj={}". format(task.taskid, task._objecttype, task._object)) # 若全部子任务都已发送(不管发成功还是失败),且子任务没有发送成功的, # 则更新总任务为失败,并返回回馈数据 if not self._dbmanager.update_iscouttask_status( task._platform, task.taskid, ECommandStatus.Failed): self._logger.error( "Update IScoutTask cmdstatus to {} faled: taskid:{}". format(ECommandStatus.Failed.name, task.taskid)) # 失败,返回总任务回馈数据 tb: IscoutTaskBack = IscoutTaskBack.create_from_task( task, ECommandStatus.Failed, "任务执行失败,发送到采集端失败") if not OutputManagement.output(tb): self._logger.error( "Write IscoutTaskBack failed:\ntaskid:{}".format( task.taskid)) except Exception as ex: self._logger.error( "Merge IScoutTask status error:\nplatform:{}\ntaskid:{}\nerror:{}" .format(task._platform, task.taskid, ex.args)) self._dbmanager.update_iscouttask_status(task._platform, task.taskid, ECommandStatus.Failed)
def _generate_task_back_percent(self, task: IscoutTask) -> bool: """返回总任务百分比""" res: bool = False try: currpercent = math.floor(task.batchcompletecount / task.batchtotalcount * 100) lastprogress = task.progress * 100 if task.batchtotalcount > 100: # 子任务数大于100个的,每1%返回一次 if currpercent - lastprogress < 1: res = True elif 50 < task.batchtotalcount <= 100: # 50<x<=100个子任务的,总共返回25个百分比文件,每%4返回一次 if currpercent - lastprogress < 4: res = True else: # 0<x<=50个子任务的,每%10左右返回一次 if currpercent - lastprogress < 10: res = True if res: return res # 最新总任务Progress更新到数据库并发送回馈数据 task.progress = currpercent / 100 task.cmdstatus = ECommandStatus.Progress if not self._dbmanager.update_iscout_task2(task): self._logger.error( "Update IScoutTask with progress failed: taskid={} objecttype={} progress={}" .format(task.taskid, task._objecttype.name, task.progress)) return res taskback: IscoutTaskBack = IscoutTaskBack.create_from_task( task, ECommandStatus.Progress, recvmsg='{}%'.format(currpercent), batchcompletecount=task.batchtotalcount) if not OutputManagement.output(taskback): res = False self._logger.error( "Output IscoutTaskBack progress failed:\ntaskid:{}\ncmdstatus:{}\nprogress:{}" .format(task.taskid, task.cmdstatus.name, currpercent)) return res res = True self._logger.info( "IscoutTaskBack generated [Progress {}]:\ntaskid={}".format( task.progress, task.taskid)) except Exception: res = False self._logger.error( "Generate IscoutTaskBack for batch complete percent error:\ntaskid:{}\nerror:{}" .format(task.taskid, traceback.format_exc())) finally: pass return res
def _update_to_db(self, task: IscoutTask, targetclient: Client, succ: bool): """同步任务下发状态到数据库。这里来的永远是子任务""" try: task.laststarttime = helper_time.ts_since_1970_tz() updatefields: dict = {} updatefields["PeriodNum"] = task.periodnum if not succ: # 失败,返回回馈数据 task.lastendtime = helper_time.ts_since_1970_tz() updatefields["LastEndTime"] = task.lastendtime task.cmdstatus = ECommandStatus.Failed task.cmdrcvmsg = "发送任务到采集端失败" tb: IscoutBtaskBack = IscoutBtaskBack.create_from_task( task, cmdstatus=task.cmdstatus, recvmsg=task.cmdrcvmsg) if not OutputManagement.output(tb): self._logger.error( "Write IscoutBtaskBack failed:\ntaskid:{}".format( task.taskid)) if isinstance(task.cmd, IdownCmd): task.cmd.cmdstatus = ECommandStatus.Failed task.cmd.cmdrcvmsg = task.cmdrcvmsg cmdback: CmdFeedBack = CmdFeedBack.create_from_cmd( task.cmd, task.cmd.cmdstatus, task.cmd.cmdrcvmsg) if not OutputManagement.output(cmdback): self._logger.error( "Write IDownCmdBack failed:\nplatform:{}\ncmdid:{}" .format(task._platform, task.cmd_id)) else: # 成功 task.cmdstatus = ECommandStatus.Dealing if isinstance(task.cmd, IdownCmd): task.cmd.cmdstatus = ECommandStatus.Dealing # 返回 子任务开始回馈 task.cmdstatus = ECommandStatus.Dealing task.cmdrcvmsg = "任务开始执行" if task.periodnum > 1: task.cmdrcvmsg += ",周期{}".format(task.periodnum) tb: IscoutBtaskBack = IscoutBtaskBack.create_from_task( task, cmdstatus=task.cmdstatus, recvmsg=task.cmdrcvmsg) if not OutputManagement.output(tb): self._logger.error( "Write IscoutBtaskBack failed:\ntaskid:{}".format( task.taskid)) self._logger.info( "Send IScoutTask succeed [{}: {}]:\ntaskid:{}\nbatchid:{}\nperiod:{}\nclient:{}\t{}" .format( task._objecttype.name, task._object, task.taskid, task.batchid, task.periodnum, task._clientid, targetclient._statusbasic.ip, )) with self._dbmanager.get_automic_locker( EDBAutomic.ReduplicateIScoutTask): # 总任务batchcompletecount -1 # 子任务isbatchcompletecountincreaced 置0 self._dbmanager.decreace_iscouttask_batch_complete_count( task._platform, task.taskid, task.batchid) task.batchcompletecount -= 1 # 更新数据库当前子任务状态 updatefields["Status"] = task.cmdstatus.value updatefields["LastStartTime"] = task.laststarttime if not self._dbmanager.update_iscoutbtask( task._platform, task.taskid, task.batchid, updatefields): # 这里如果更新数据库状态失败了,那发送线程可能会重新发送当前子任务。 # 此时需要采集端支持 冥等性(任务去重,保证多次收到同一条任务只会处理一条) self._logger.error( "Update IScoutBatchTask cmdstatus failed:\ntaskid:{}\ncmdstatus:{}" .format(task.taskid, task.cmdstatus.name)) # 更新总任务开始时间 if not self._dbmanager.update_iscout_task( task._platform, task.taskid, updatefields={ "LastStartTime": helper_time.ts_since_1970_tz(), "PeriodNum": task.periodnum, }, ): self._logger.error( "Update IScouttask LastStartTime failed:\ntaskid:{}\ncmdstatus:{}" .format(task.taskid, task.cmdstatus.name)) # 如果带cmd,更新cmd状态 if isinstance( task.cmd, IdownCmd) and not self._dbmanager.update_cmd_status( task.cmd.platform, task.cmd.cmd_id, targetclient._statusbasic._clientid if not targetclient is None else task._clientid, task.cmd.cmdstatus, ): self._logger.error( "Update cmd cmdstatus failed:\ntaskid:{}\ncmdstatus:{}" .format(task.taskid, task.cmdstatus.name)) # 返回 总任务开始回馈 task.cmdstatus = ECommandStatus.Dealing task.cmdrcvmsg = "任务开始执行,周期{}".format(task.periodnum) tb: IscoutTaskBack = IscoutTaskBack.create_from_task( task, cmdstatus=task.cmdstatus, recvmsg=task.cmdrcvmsg, batchcompletecount=task.batchcompletecount, periodnum=task.periodnum, ) if not OutputManagement.output(tb): self._logger.error( "Write IscoutBtaskBack failed:\ntaskid:{}".format( task.taskid)) except Exception: self._logger.error("Update task cmdstatus to db error: {}".format( traceback.format_exc())) self._dbmanager.update_iscouttask_status(task._platform, task.taskid, ECommandStatus.Failed) if isinstance(task.cmd, IdownCmd): self._dbmanager.update_cmd_status( task._platform, task.cmd_id, task.cmd._clientid, ECommandStatus.Failed, )