Ejemplo n.º 1
0
def excTasks(tasks):
    job_defaults = {'max_instances': 2}
    scheduler = BlockingScheduler(job_defaults=job_defaults)
    if tasks is not None:
        if isinstance(tasks[0], list):
            for task in tasks:
                addTask(scheduler, task)
        else:
            addTask(scheduler, tasks)
    scheduler.add_listener(my_listener, EVENT_JOB_EXECUTED | EVENT_JOB_ERROR)
    try:
        scheduler.start()
    except (KeyboardInterrupt, SystemExit):
        scheduler.pause()
Ejemplo n.º 2
0
def my_listener(event):
    if event.exception:
        print("保存出错信息")
        # 如果出现失误,首先将出错的消息发给服务器
        # 日志记录下来
        #1.直接关闭任务调度器
        scheduler.resume()
        print("任务出错了!!!")
    else:
        print('任务照常进行...')


if __name__ == '__main__':

    scheduler = BlockingScheduler()

    scheduler.add_job(job2,
                      trigger='cron',
                      second='*/5',
                      args=['hello', 'world'])

    scheduler.add_job(job1, trigger='cron', second='*/5')
    #每天整点运行
    # scheduler.add_job(
    #     get_craw_data,
    #     trigger='cron',
    #     #hour='0-23',
    #     minute='0-59',
    # )
    scheduler.add_listener(my_listener, EVENT_JOB_EXECUTED | EVENT_JOB_ERROR)
    scheduler.start()
Ejemplo n.º 3
0
class Scheduler:
    def __init__(self):
        conf = configparser.ConfigParser()
        conf.read("../agent.ini")
        ip = conf.get("redis", "ip")
        port = conf.getint("redis", "port")
        timeout = conf.getint("redis", "timeout")
        self.invoker_id = self._get_invoker_id()
        self.max_tasks = conf.getint("invoker", "max_tasks")
        self.live_seconds = conf.getint("invoker", "live_seconds")
        self.db = SchedulerDb(ip, port, timeout)
        logging.config.fileConfig("../logger.ini")
        self.logger = logging.getLogger("main")
        executors = {
            'default': {'type': 'processpool', 'max_workers': self.max_tasks + 1}
        }
        self.blockScheduler = BlockingScheduler()
        self.jobs = {}
        self.lock = threading.Lock()

    @staticmethod
    def _get_invoker_id():
        hostname = socket.gethostname()
        pid = os.getpid()
        return hostname + "-" + str(pid)

    def task_invoke(self, task_instance, task_param):
        if task_param.cmd.startswith('http'):
            executor = HttpExecutor(self.db, task_instance, task_param)
            executor.execute()
        else:
            pass

    def break_heart(self):
        """
        invoker每隔一段时间就心跳一下,看看是否有新任务,是否有任务需要更新
        :param bs:
        :return:
        """
        # 先看看参数是否有变化的把调度重启或者关闭
        try:
            self.lock.acquire()
            self.refresh_local_invoker()
            self.refresh_other_invokers()
            if len(self.jobs) >= self.max_tasks:
                return

            task_instances, task_params = self.db.query_waiting_run_tasks(self.invoker_id,
                                                                          self.max_tasks - len(self.jobs),
                                                                          True)
            if len(task_instances) == 0:
                return
            for i in range(len(task_instances)):
                task_instance = task_instances[i]
                task_param = task_params[i]
                if task_instance.id not in self.jobs.keys():
                    self.logger.info("分配了新任务%s", task_instance.id)
                    job = self.blockScheduler.add_job(self.task_invoke,
                                                      next_run_time=(
                                                          datetime.datetime.now() + datetime.timedelta(seconds=2)),
                                                      args=[task_instance, task_param], id=task_instance.id)
                    self.jobs[job.id] = job
                    self.db.lock_invoker_instance(self.invoker_id, task_instance.id, self.live_seconds)
                else:
                    self.logger.error("%s任务已经在运行", task_instance.id)
        finally:
            self.lock.release()

    def refresh_local_invoker(self):
        """
        调度的参数是否发生变化,如有需要重启调度
        :param bs:
        :return:
        """

        self.db.update_invoker_time(self.invoker_id, self.jobs.keys(), self.live_seconds)
        self.logger.info("%s心跳更新成功!", self.invoker_id)
        # 看看是否有需要停止的任务再自己这里,释放掉
        stop_tasks = self.db.query_need_stop_tasks(self.invoker_id)
        for stop_task in stop_tasks:
            if stop_task in self.jobs.keys():
                try:
                    job = self.jobs[stop_task]
                    task_instance = job.args[0]
                    task_instance.status = 'off'
                    job.pause()
                    job.remove()
                except Exception as e:
                    self.logger.error(e)
                    self.jobs.pop(stop_task)
                    try:
                        self.blockScheduler.remove_job(stop_task)
                    except Exception as e1:
                        self.logger.error(e1)

            self.logger.info("人工停止了任务%s", stop_task)
            self.db.unlock_invoker_instance(self.invoker_id, stop_task, self.live_seconds)

        # 是否有参数变化的任务需要重启
        c_jobs = copy.copy(self.jobs)
        for key in c_jobs.keys():
            if key not in self.jobs.keys():
                continue
            job = self.jobs[key]
            task_instance = job.args[0]
            old_task_param = job.args[1]
            # 判断参数是否发生变化,如果有变化重新执行任务
            new_task_param = self.db.query_task_param(task_instance.task_param_id)
            # if new_task_param
            if not new_task_param.has_diff(old_task_param):
                continue

            try:
                task_instance.status = 'off'
                job.pause()
                job.remove()
            except Exception as e:
                self.logger.error(e)
                self.jobs.pop(key)
                try:
                    self.blockScheduler.remove_job(key)
                except Exception as e1:
                    self.logger.error(e1)
            self.logger.info("参数变化停止了任务%s", task_instance.id)
            self.db.unlock_invoker_instance(self.invoker_id, task_instance.id, self.live_seconds)
            self.db.add_task_waiting_run(task_instance.id)

    def refresh_other_invokers(self):
        """
        遍历所有的invoker,判断invoker是否超过存活期
        :return:
        """
        invokers = self.db.query_all_invokers()
        for invoker_id in invokers.keys():
            if not self.db.invoker_is_live(self.invoker_id):
                task_instance_list = self.db.query_invoker_tasks(self.invoker_id)
                for task_instance_id in task_instance_list:
                    self.db.add_task_waiting_run(task_instance_id)

    def main(self):
        try:
            self.db.register_invoker(self.invoker_id, self.max_tasks, self.live_seconds);
            self.blockScheduler.add_listener(self._job_listener,
                                             events.EVENT_JOB_ERROR | events.EVENT_JOB_MISSED)

            self.blockScheduler.add_job(self.break_heart, "interval", seconds=self.live_seconds / 2,
                                        id="break_heart")
            self.logger.info("开始启动调度...")
            self.blockScheduler.start()
            self.logger.info("启动调度成功!")
        except KeyboardInterrupt as e:
            self.logger.info(e)
            self.blockScheduler.shutdown()

    def _job_listener(self, ev):
        """
        监听job的事件,job完成后再发起下次调用,对于异常也要处理
        :param ev:
        :return:
        """
        if ev.code == events.EVENT_JOB_ERROR:
            self.logger.error(ev.exception)
            self.logger.error(ev.traceback)
        else:
            pass
Ejemplo n.º 4
0
class EventScheduler:
    def __init__(self, reporter: ResultReporter):
        self.reporter = reporter
        self.scheduler = BlockingScheduler()
        self.events = list()
        log_path = static_setting.settings["CaseRunner"].log_path
        log_file = os.path.join(log_path, "event_scheduler_log.log")
        self.log = logger.register("EventScheduler",
                                   filename=log_file,
                                   for_test=True)
        self.scheduler.add_listener(self._event_listen, EVENT_JOB_EXECUTED)

    def add_event(self,
                  event,
                  package,
                  args,
                  is_background,
                  need_lock,
                  start_time,
                  interval=5,
                  loop_count=1,
                  description=""):
        m = importlib.import_module(package)
        event_cls = getattr(m, event)
        new_event = event_cls(description, log=self.log)
        new_event.need_lock = need_lock
        new_event.back_ground = is_background
        new_event.arguments = args
        new_event.interval = interval
        new_event.loop_count = loop_count
        # 生成一个STEP 的节点给Event操作
        new_event.reporter = self.reporter.add_event_group(f"Event: {event}")

        if is_background:
            new_event.job = self.scheduler.add_job(new_event.run,
                                                   "interval",
                                                   seconds=interval,
                                                   start_date=start_time,
                                                   id=f"{event}{uuid.uuid4()}")
        else:
            new_event.job = self.scheduler.add_job(new_event.run,
                                                   "date",
                                                   run_date=start_time,
                                                   id=f"{event}{uuid.uuid4()}")
        self.events.append(new_event)

    def remove_event(self, event_id):
        job = self.scheduler.get_job(event_id)
        if job:
            event_to_remove = None
            for event in self.events:
                if event.job == job:
                    event_to_remove = event
                    self.scheduler.remove_job(event_id)
                    break
            if event_to_remove:
                self.events.remove(event_to_remove)

    def start(self):
        self.scheduler.start()

    def _event_listen(self, job):
        for event in self.events:
            if event.job.id == job.job_id:
                if event.back_ground:
                    return
                else:
                    if event.loop_count == 1:
                        return
                    delta = datetime.timedelta(seconds=event.interval)
                    next_date = job.scheduled_run_time + delta
                    event.job = self.scheduler.add_job(
                        event.run,
                        "date",
                        run_date=next_date,
                        id=f"{event.name}{uuid.uuid4()}")
                    event.loop_count -= 1
                    return
Ejemplo n.º 5
0
class ActionScheduler:
    def __init__(self):
        self.scheduler = BlockingScheduler(jobstores=APSCHEDULER_SETTINGS['jobstores'],
                                           executors=APSCHEDULER_SETTINGS['executors'],
                                           job_defaults=APSCHEDULER_SETTINGS['job_defaults'],
                                           timezone=TIMEZONE_PST8PDT)
        pass

    def start(self):
        self._add_event_listener()
        # self._add_example_jobs()
        self._add_jobs()
        self.scheduler.start()

    def shutdown(self):
        # self.scheduler.remove_all_jobs()  # save all jobs into sqlite, do not remove them
        self.scheduler.shutdown()

    def _add_event_listener(self):
        self.scheduler.add_listener(ActionScheduler.listener_jobs_status, EVENT_JOB_EXECUTED | EVENT_JOB_ERROR)
        self.scheduler.add_listener(ActionScheduler.listener_all_jobs_finished, EVENT_ALL_JOBS_REMOVED)

    # examples
    def _add_example_jobs(self):
        import datetime
        self.scheduler.add_job(func=ActionScheduler.job_example, args=["cron", ], trigger='cron', second='*/5',
                               misfire_grace_time=DEFAULT_MISFIRE_GRACE_TIME, replace_existing=True, id="cron")
        self.scheduler.add_job(func=ActionScheduler.job_example, args=["interval", ], trigger='interval', seconds=60,
                               misfire_grace_time=DEFAULT_MISFIRE_GRACE_TIME, replace_existing=True, id="interval")
        self.scheduler.add_job(func=ActionScheduler.job_example, args=["date", ], trigger='date',
                               run_date=get_cur_time()+datetime.timedelta(seconds=12), id="date")

    # examples
    @staticmethod
    def job_example(job_type):
        print("job_example: {}".format(job_type))

    def _add_jobs(self):
        # add reap alerts immediate job TODO test
        # self.scheduler.add_job(id="reap_alerts_immediate", func=ActionScheduler.job_reap_alerts_and_start_action_tasks, args=[],
        #                        misfire_grace_time=DEFAULT_MISFIRE_GRACE_TIME, replace_existing=True, )
        # add reap alerts interval job
        # self.scheduler.add_job(id="reap_alerts", func=ActionScheduler.job_reap_alerts_and_start_action_tasks,
        #                        args=[], trigger='interval', seconds=REAP_INTERVAL_SECONDS,
        #                        misfire_grace_time=DEFAULT_MISFIRE_GRACE_TIME, replace_existing=True, )
        # add gather & retry failed action tasks immediate job TODO test
        # self.scheduler.add_job(id="check_tasks_immediate", func=ActionScheduler.job_gather_and_retry_failed_action_tasks, args=[],
        #                        misfire_grace_time=DEFAULT_MISFIRE_GRACE_TIME, replace_existing=True, )
        # add gather & retry failed action tasks interval job
        # self.scheduler.add_job(id="check_tasks", func=ActionScheduler.job_gather_and_retry_failed_action_tasks,
        #                        args=[], trigger='interval', seconds=GATHER_FAILED_TASKS_INTERVAL_SECONDS,
        #                        misfire_grace_time=DEFAULT_MISFIRE_GRACE_TIME, replace_existing=True, )
        pass

    @staticmethod
    def listener_all_jobs_finished(event):  # this would hardly be invoked
        logger_.info('All jobs are done.')

    @staticmethod
    def listener_jobs_status(event):
        if event.exception:
            logger_.warn('Job {} crashed.'.format(event.job_id))
        else:
            logger_.info('Job {} executed.'.format(event.job_id))
Ejemplo n.º 6
0
    '''
    if isinstance(event, JobSubmissionEvent):
        print("任务{}触发执行".format(event.job_id))
    if isinstance(event, JobExecutionEvent) and event.exception:
        print("任务{}抛出异常:{}".format(event.job_id, event.exception))

jobstores = {
    'default': SQLAlchemyJobStore(url='sqlite:///db.sqlite3')  #定时器任务持久化地址
}

scheduler = BlockingScheduler(jobstores=jobstores)

scheduler.add_job(func=aps_test,
                  trigger=CronTrigger(hour=20, minute=48),
                  replace_existing=True,
                  id="sb")

scheduler.add_job(func=aps_test,
                  replace_existing=True,
                  trigger=DateTrigger(run_date=datetime.datetime.now() + datetime.timedelta(seconds=12)),
                  id="sbsb")

scheduler.add_job(func=aps_test,    # 任务函数
                  trigger=IntervalTrigger(seconds=5),       # 执行计划
                  replace_existing=True,
                  id="sbsbsb"           # 唯一的
                  )

scheduler.add_listener(my_listener)
scheduler.start()
Ejemplo n.º 7
0
class TaskExecutor:
    def __init__(self, db, task_instance, task_param):
        self.task_instance = task_instance
        self.task_param = task_param
        self.db = db
        # invoke log
        self.invoke_log_map = {}
        self.jobs = {}
        logging.config.fileConfig("../logger.ini")
        self.logger = logging.getLogger("taskExecutor")
        invoke_count = int(self.task_param.get_invoke_args()['invoke_count'])
        executors = {
            'default': {
                'type': 'threadpool',
                'max_workers': invoke_count + 1
            }
        }
        self.scheduler = BlockingScheduler(executors=executors)

    def execute(self):
        self.scheduler.add_listener(
            self._job_listener,
            events.EVENT_JOB_EXECUTED | events.EVENT_JOB_ERROR
            | events.EVENT_JOB_ADDED | events.EVENT_JOB_MISSED)

        # invoke_log_map up server
        self.scheduler.add_job(self._invoke_break_heart, "interval", seconds=2)
        try:
            self.scheduler.start()
        except Exception as e:
            print(e)
            self.scheduler.shutdown(wait=True)

    def _job_listener(self, ev):
        """
        监听job的事件,job完成后再发起下次调用,对于异常也要处理
        :param ev:
        :return:
        """
        if self.task_instance.status == 'off':
            return
        if ev.code == events.EVENT_JOB_ADDED:
            self.jobs[ev.job_id] = self.scheduler.get_job(ev.job_id)
        elif ev.code == events.EVENT_JOB_EXECUTED or ev.code == events.EVENT_JOB_ERROR:
            if ev.code == events.EVENT_JOB_ERROR:
                self.logger.error(ev.exception)
                self.logger.error(ev.traceback)
            job = self.jobs[ev.job_id]
            self.scheduler.add_job(
                job.func,
                next_run_time=(datetime.datetime.now() +
                               datetime.timedelta(seconds=1)),
                id=ev.job_id,
                args=job.args)
        else:
            pass

    def _invoke_break_heart(self):
        if self.task_instance.status == 'off':
            jobs = self.scheduler.get_jobs()
            for job in jobs:
                try:
                    job.pause()
                    job.remove()
                except Exception as e:
                    self.logger.error(e)
        self.db.save_task_logs(self.invoke_log_map)
Ejemplo n.º 8
0
    parser.add_argument(
        '--log',
        choices=['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'],
        default='WARNING',
        help="Log level")
    args = parser.parse_args()

    logging.basicConfig(level=getattr(logging, args.log))

    config = configparser.ConfigParser()
    config.read_file(args.config_file)

    scheduler = BlockingScheduler()

    scheduler.add_listener(
        lambda event: logging.error("Exception in feed fetch:",
                                    exc_info=event.exception), EVENT_JOB_ERROR)

    interval = int(config['interval']['interval'], 10)
    agency_ids = [
        key.split(':')[1] for key in config.keys() if key.startswith('agency:')
    ]

    for agency_id in agency_ids:
        for feed in config['agency:' + agency_id].items():
            (feed_id, feed_url) = feed
            scheduler.add_job(get,
                              'interval', (agency_id, feed_id, feed_url,
                                           config['influxdb'], interval / 2),
                              seconds=interval,
                              id=agency_id + ":" + feed_id)
Ejemplo n.º 9
0
class TimerWork():

    def __init__(self):
        self.jobs = []
        self.sched = BlockingScheduler()
        self.sched.add_listener(self.listener, EVENT_JOB_ERROR | EVENT_JOB_EXECUTED)

    def listener(self, event):
        if event.exception:
            print 'JOB :<'
        else:
            print 'JOB :>'
        pass

    def exit(self):
        print 'shutdown now'
        self.sched.shutdown(wait=True)
        print 'shutdown ok'
        pass

    def pause(self):
        BaseScheduler.pause_job()
        pass

    def resume(self):
        BaseScheduler.remove_job()
        pass

    def add_job(self, func, gap_time=0, first_run_time=None, args=None, kwargs=None):
        '''
        添加定时任务
        :param func: 执行函数
        :param gap_time: 间隔时间,如果设置小于等于0的值忽略 单位s
        :param first_run_time: 第一次执行时间 datetime.datetime 如果不设置就按正常处理
        :param args: 参数
        :param kwargs: 参数
        :return:
        '''
        self.jobs.append(func)
        if type(first_run_time) == types.IntType:
            first_run_time = datetime.datetime.now() + datetime.timedelta(seconds=first_run_time)
        if gap_time > 0:
            if first_run_time:
                self.sched.add_job(func, 'interval', seconds=gap_time, next_run_time=first_run_time, args=args, kwargs=kwargs)
            else:
                self.sched.add_job(func, 'interval', seconds=gap_time, args=args,
                                   kwargs=kwargs)
        else:
            if first_run_time:
                self.sched.add_job(func, next_run_time=first_run_time, args=args, kwargs=kwargs)
                pass
            else:
                self.sched.add_job(func, args=args, kwargs=kwargs)
                pass
        pass

    def run(self):
        if len(self.jobs) > 0:
            self.sched.start()
        else:
            print 'no add jobs , so check'
Ejemplo n.º 10
0
class JobLauncher(object):
    def __init__(self, background=False, deamon=True, **kwargs):
        logging.basicConfig(format="[%(asctime)s] %(message)s",
                            atefmt="%Y-%m-%d %H:%M:%S")
        logging.getLogger('apscheduler').setLevel(logging.DEBUG)

        if background:
            self.sched = BackgroundScheduler(deamon=deamon)  # background
        else:
            self.sched = BlockingScheduler(deamon=deamon)  # foreground

        # TODO: Read from configuration file.
        self.sched.configure(
            jobstores={
                # "sqlite": SQLAlchemyJobStore(url='sqlite:///app/database/example.db'),
                # "default": MemoryJobStore()
                "default":
                SQLAlchemyJobStore(url='sqlite:///app/database/example.db')
            },
            executors={
                'default': ThreadPoolExecutor(20),
                'processpool': ProcessPoolExecutor(5)
            },
            job_defaults={
                'coalesce': False,
                'max_instances': 3
            },
            timezone=get_localzone()  # Asia/Seoul
        )

        self.retried = 0
        self.logger = logging.getLogger('apscheduler')

        super(JobLauncher, self).__init__()

    def start(self):
        try:
            if self.sched.state != STATE_RUNNING:
                self.printJobs(jobstore='default')
                started = self.sched.start()

        except ConflictingIdError as e:
            traceback.print_exc()

        except KeyboardInterrupt as e:
            traceback.print_exc()

        finally:
            pass
            # Remove all remained store.
            # self.sched.remove_all_jobs()
            # for job in self.getJobs():
            #   if job.pending:
            #     job.pause()

            self.logger.info('Finished')
            self.logger.info(self.getJobs())
            self.printJobs()

    def stop(self, wait=False):
        if self.sched.state == STATE_RUNNING:
            self.sched.shutdown(wait=wait)

    def resume(self):
        if self.sched.state == STATE_RUNNING:
            self.sched.resume()

    def pause(self):
        if self.sched.state == STATE_RUNNING:
            self.sched.pause()

    def addListener(self, listener, types):
        self.sched.add_listener(listener, types)

    def addJob(self, job, **kwargs):
        execute, trigger, options = job.build(**kwargs)

        added_job = self.sched.add_job(execute, trigger, **options)

        self.printJobs()

        return added_job

    def getJob(self, job_id):
        return self.sched.get_job(job_id)

    def getJobs(self, jobstore=None):
        return self.sched.get_jobs(jobstore=jobstore)

    def removeJob(self, job_id, jobstore=None):
        return self.sched.remove_job(job_id, jobstore=jobstore)

    def removeAllJob(self, jobstore=None):
        return self.sched.remove_all_jobs(jobstore=jobstore)

    def printJobs(self, jobstore=None, out=None):
        return self.sched.print_jobs(jobstore=jobstore, out=None)

    def getJobState(self, job_id=None, jobstore=None):
        state = list()

        if job_id is not None:
            job = self.sched.get_job(job_id, jobstore=jobstore)

            if job is not None:
                temp = dict()
                temp[job.id] = {
                    "next_run_time": job.next_run_time,
                    "state": job.pending,
                }
                state.append(temp)

        else:
            for job in self.sched.get_jobs(jobstore=jobstore):
                temp = dict()
                temp[job.id] = {
                    "next_run_time": job.next_run_time,
                    "state": job.pending,
                }
                state.append(temp)

        return state