前言
django提供了commands类,允许我们编写命令行脚本,并且可以通过python manage.py拉起。
了解commands
具体django commands如何使用,大家参考官方文档即可:https://docs.djangoproject.com/en/2.2/howto/custom-management-commands/
一个坑
使用时遇到一个坑:在commands运行中的异常并不会打印到屏幕上,它要求我们必须抛出commanderror类型的异常才能被打印到屏幕中,具体参考:https://docs.djangoproject.com/en/2.2/howto/custom-management-commands/#command-exceptions
文件锁防并发
我们通常利用crontab拉起定时任务,那么就会面临一个常见问题,如何避免前一次没结束而后一次再次启动的问题。
通常都是用文件锁来搞定这个事情,我做了一个简单的装饰器来包装commands的handle方法,定义一套元类或者类装饰器都可以达到同样的目的,这里就不炫技了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
# -*- coding: utf-8 -*- import fcntl import os from apps.settings import cron_lock_dir # 尝试加锁 def try_lock(name): def decorator(func): def wrap( * args, * * kwargs): os.makedirs(cron_lock_dir, exist_ok = true) with open ( '{}/{}' . format (cron_lock_dir, name), 'w' ) as fd: try : fcntl.lockf(fd, fcntl.lock_ex | fcntl.lock_nb) # 加锁 func( * args, * * kwargs) fcntl.lockf(fd, fcntl.lock_un) # 解锁 except : # 加锁异常跳过 pass return wrap return decorator |
其中cron_lock_dir是文件锁的父目录,下面放了若干锁文件。
对commands的handle方法指定锁文件名即可:
1
2
3
4
|
class command(basecommand): @try_lock ( 'check_order' ) # 指定锁文件的名字 def handle( self , * args, * * options): pass |
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对服务器之家的支持。
原文链接:https://yuerblog.cc/2019/05/13/django-防止定时任务并发/