首页   注册   登录
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX  ›  Django

关于 django 使用 apscheduler 一次任务被重复执行问题

  •  
  •   fanne · 2018-01-15 17:17:43 +08:00 · 4239 次点击
    这是一个创建于 690 天前的主题,其中的信息可能已经有所发展或是发生改变。

    APSwork 部分内容

    redis_connet = redis.Redis(host='localhost', port=6379, db=0)
    
    jobstores = {
        'redis': RedisJobStore(),
        }
    executors = {
        'default': ThreadPoolExecutor(4)
        }
    sched = BackgroundScheduler(jobstores=jobstores, executors=executors)
    
    def open_in(servername,serverip,cmd):
        print '{0}--open in ....'.format(servername)
        .....
    
    def open_out(servername,serverip,cmd):
        print '{0}---open out ....'.format(servername)
        .....
    
    def cronKaifu(starttime,servername,serverip,cmd_in,cmd_out):
        ....
    
        jobstores = {
            'redis': RedisJobStore(),
        }
        executors = {
            'default': ThreadPoolExecutor(1)
            # 'processpool': ProcessPoolExecutor(3)
        }
        sched = BackgroundScheduler(jobstores=jobstores, executors=executors)
    		sched.add_job(func=open_in,args=(servername,serverip,cmd_in,),trigger='date',next_run_time=open_in_time,jobstore='redis',id='{0}_in_{1}'.format(servername,sendtime_timestamp_in))
        print sched.get_jobs()
        
        
        sched.add_job(func=open_out,args=(servername,serverip,cmd_out,),trigger='date',next_run_time=open_out_time,jobstore='redis',id='{0}_out_{1}'.format(servername,sendtime_timestamp_out))
        print sched.get_jobs()
        sched.start()
    
    

    views.py 里面调用这个任务

    def kaifu_time(request):
    	....
    	....
    	cronKaifu(timeArray,server_name,server_ip,open_in_cmd,open_out_cmd)
    	......
    	....
    	return render(request, 'mt/kaifu_time.html', locals())
    

    添加任务后,两次打印 get_jobs()内容

    [<Job (id=mt_ios999game_in_1516005540000 name=open_in)>]
    [<Job (id=mt_ios999game_in_1516005540000 name=open_in)>, <Job (id=mt_ios999game_out_1516006260000 name=open_out)>]
    

    到点后,id=mt_ios999game_in_1516005540000,会被执行 2 次,有时候会是 3 次,但有时候又是正常的。

    [15/Jan/2018 15:02:22] "POST /mt/kaifu_time/ HTTP/1.1" 302 0
    [15/Jan/2018 15:02:22] "GET /mt/kaifu_time HTTP/1.1" 301 0
    [15/Jan/2018 15:02:22] "GET /mt/kaifu_time/ HTTP/1.1" 200 19539
    mt_ios999game--open in ....
    mt_ios999game--open in ....  <==这里的打印两次
    Exception in thread APScheduler:
    Traceback (most recent call last):
      File "/usr/local/lib/python2.7/threading.py", line 801, in __bootstrap_inner
        self.run()
      File "/usr/local/lib/python2.7/threading.py", line 754, in run
        self.__target(*self.__args, **self.__kwargs)
      File "/qzdata1/python_env/LazyOps/lib/python2.7/site-packages/apscheduler/schedulers/blocking.py", line 30, in _main_loop
        wait_seconds = self._process_jobs()
      File "/qzdata1/python_env/LazyOps/lib/python2.7/site-packages/apscheduler/schedulers/base.py", line 981, in _process_jobs
        self.remove_job(job.id, jobstore_alias)
      File "/qzdata1/python_env/LazyOps/lib/python2.7/site-packages/apscheduler/schedulers/base.py", line 613, in remove_job
        raise JobLookupError(job_id)
    JobLookupError: u'No job by the id of mt_ios999game_in_1516005540000 was found'
    

    我把两个 add_job()位置互掉后,即先添加 add_job(func=open_out...) 再添加 add_job(func=open_in..)

    然后 open_out 会被执行两次。

    这样的问题,我应如何修改。

    感觉毫无逻辑出现这问题,一次性任务,会被重复执行,而且是同一时间的。

    6 回复  |  直到 2019-11-12 08:50:42 +08:00
        1
    oncew   2018-07-30 15:46:46 +08:00
    偶然看到这个问题,虽然很久了,但是回复一下可能的原因:你的程序运行的是 debug 模式,或者多进程,多线程模式时候,会有多个 scheduler 实例,这个时候会造成任务多次执行
        2
    fanne   2018-07-30 15:58:17 +08:00
    @oncew #1 嗯,很大可能是的,后面遇到一个情况,有个 java 项目,因为某种原因起了两个进程,然后每日日报分析的时候,就多了一倍,然后我想到,我这个问题也有可能是类似问题造成的,不过当时没找到原因,就把这个功能撤了,就没有去测试。

    为了图简便,我的项目程序,直接 python manage.py runserver 丢后台跑
    然后有天我发现,我其实每次重启项目,这个进程都没停止掉就又起了一个,然后发现是有好多个进程的

    所以,很大可能是你描述的这个问题。
        3
    oncew   2018-09-06 06:45:16 +08:00
    v2ex 的提醒功能做的不好,看其他消息提醒的时候,才注意这个帖子.. 重复执行的原因我能确定是多进程造成的问题,后面看了下 apschedler 的源码,对于多线程的情况是有加锁执行任务的,防止重复执行(希望没记错--),但是多进程的情况,这个线程锁没用,debug 模式(也会多起一个进程监听),后面我尝试加了一个多进程的锁,发现许多坑仍然没有解决,实现的功能也是 celery 已经早就解决的问题,所以我觉得用 celery 是最好的解决方案
        4
    mingxu   2018-09-11 10:42:03 +08:00
    相比 APScheduler,celery 不能实现动态添加任务的功能吧。这个问题还有其他的解决办法么?
        5
    boyzhh   25 天前
    我也遇到这个问题了,最简单的提交表格新建记录,经过反复测试,随机性的出现一个 view 同时执行两次,导致报错记录已存在,但因为执行了两次,新的记录也能存入,测试大概是 7-10 次就会出现一次同时执行两次的情况,莫名其妙,关闭了 debug 模式也一样
        6
    fanne   24 天前
    @boyzhh 后面有定位到哪问题么。
    关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   966 人在线   最高记录 5043   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.3 · 23ms · UTC 23:04 · PVG 07:04 · LAX 15:04 · JFK 18:04
    ♥ Do have faith in what you're doing.