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

2018-01-15 17:17:43 +08:00
 fanne

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 会被执行两次。

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

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

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

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

所以,很大可能是你描述的这个问题。
oncew
2018-09-06 06:45:16 +08:00
v2ex 的提醒功能做的不好,看其他消息提醒的时候,才注意这个帖子.. 重复执行的原因我能确定是多进程造成的问题,后面看了下 apschedler 的源码,对于多线程的情况是有加锁执行任务的,防止重复执行(希望没记错--),但是多进程的情况,这个线程锁没用,debug 模式(也会多起一个进程监听),后面我尝试加了一个多进程的锁,发现许多坑仍然没有解决,实现的功能也是 celery 已经早就解决的问题,所以我觉得用 celery 是最好的解决方案
mingxu
2018-09-11 10:42:03 +08:00
相比 APScheduler,celery 不能实现动态添加任务的功能吧。这个问题还有其他的解决办法么?
boyzhh
2019-11-12 04:01:03 +08:00
我也遇到这个问题了,最简单的提交表格新建记录,经过反复测试,随机性的出现一个 view 同时执行两次,导致报错记录已存在,但因为执行了两次,新的记录也能存入,测试大概是 7-10 次就会出现一次同时执行两次的情况,莫名其妙,关闭了 debug 模式也一样
fanne
2019-11-12 08:50:42 +08:00
@boyzhh 后面有定位到哪问题么。
boyzhh
2019-12-25 02:47:26 +08:00
@fanne 恩,找到问题了,是 APPEND_SLASH=True 这个设置,就是连接结尾如果没有'/'自动加上,中间调试的时候打开这个的,也没注意,后来就间歇性出错,找了一通也没找到原因,后来努力回想改过什么配置,把这个去掉了就好了

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/423084

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX