| @@ -44,6 +44,7 @@ INSTALLED_APPS = ( | ||
| 44 | 44 | 'django.contrib.messages', | 
| 45 | 45 | 'django.contrib.staticfiles', | 
| 46 | 46 | 'rest_framework', | 
| 47 | + 'django_q', | |
| 47 | 48 | 'api', | 
| 48 | 49 | 'account', | 
| 49 | 50 | 'group', | 
| @@ -352,5 +353,18 @@ except ImportError: | ||
| 352 | 353 | try: | 
| 353 | 354 | from func_settings import redis_connect | 
| 354 | 355 |      REDIS_CACHE = redis_connect(REDIS.get('default', {})) | 
| 356 | + | |
| 357 | +    Q_CLUSTER = { | |
| 358 | + 'name': 'pai2', | |
| 359 | + 'workers': 8, | |
| 360 | + 'recycle': 500, | |
| 361 | + 'timeout': 60, | |
| 362 | + 'compress': True, | |
| 363 | + 'cpu_affinity': 1, | |
| 364 | + 'save_limit': 250, | |
| 365 | + 'queue_limit': 500, | |
| 366 | + 'label': 'Django Q', | |
| 367 | + 'redis_conn': REDIS_CACHE, | |
| 368 | + } | |
| 355 | 369 | except ImportError: | 
| 356 | 370 | REDIS_CACHE = None | 
| @@ -8,7 +8,9 @@ from django.conf import settings | ||
| 8 | 8 | from django.core.files.storage import default_storage | 
| 9 | 9 | from django.db import transaction | 
| 10 | 10 | from django.shortcuts import render | 
| 11 | +from django_q.tasks import async | |
| 11 | 12 | from logit import logit | 
| 13 | +from redis_extensions import multi_pop | |
| 12 | 14 | from rest_framework import viewsets | 
| 13 | 15 | from TimeConvert import TimeConvert as tc | 
| 14 | 16 |  | 
| @@ -20,7 +22,8 @@ from utils.error.errno_utils import LensmanStatusCode, PhotoStatusCode | ||
| 20 | 22 | from utils.error.response_utils import response | 
| 21 | 23 | from utils.ip_utils import ip_addr | 
| 22 | 24 | from utils.redis.rgroup import get_group_info, get_group_users_info, set_group_info, set_group_users_info | 
| 23 | -from utils.redis.rkeys import GROUP_LAST_PHOTO_PK | |
| 25 | +from utils.redis.rkeys import GROUP_LAST_PHOTO_PK, UUID_LIST | |
| 26 | +from utils.redis.ruuid import generate_uuids, update_uuids | |
| 24 | 27 | from utils.thumbnail_utils import make_thumbnail | 
| 25 | 28 | from utils.watermark_utils import watermark_wrap | 
| 26 | 29 |  | 
| @@ -37,8 +40,8 @@ def uuid_init(request): | ||
| 37 | 40 | """ | 
| 38 | 41 |      num = int(request.GET.get('num', 1000)) | 
| 39 | 42 |  | 
| 40 | - for i in xrange(num): | |
| 41 | - UUIDInfo.objects.create(uuid=CurtailUUID.uuid(UUIDInfo)) | |
| 43 | + # 生成 UUID | |
| 44 | + generate_uuids(num) | |
| 42 | 45 |  | 
| 43 | 46 | return response(200, 'UUID Refresh Success', u'UUID 更新成功') | 
| 44 | 47 |  | 
| @@ -55,13 +58,18 @@ def uuid(request): | ||
| 55 | 58 |      lensman_id = request.POST.get('user_id', '') | 
| 56 | 59 |      num = int(request.POST.get('num', 100)) | 
| 57 | 60 |  | 
| 58 | - uuids = UUIDInfo.objects.select_for_update().filter(status=True)[:num] | |
| 59 | - for uuid in uuids: | |
| 60 | - uuid.lensman_id = lensman_id | |
| 61 | - uuid.status = False | |
| 62 | - uuid.save() | |
| 61 | + # 从 Redis 中 Pop 中指定数量的 UUID | |
| 62 | + uuids, succeed, left = multi_pop(r, UUID_LIST, num) | |
| 63 | 63 |  | 
| 64 | - return response(200, 'Get UUID Success', u'获取唯一标识成功', [uuid.uuid for uuid in uuids]) | |
| 64 | + # 异步更新 UUID 数据库中状态 | |
| 65 | + if uuids: | |
| 66 | + async(update_uuids, lensman_id, uuids) | |
| 67 | + | |
| 68 | + # 当可用 UUID 数量少于 500 时, 异步创建 | |
| 69 | + if left < 500: | |
| 70 | + async(generate_uuids) | |
| 71 | + | |
| 72 | + return response(200, 'Get UUID Success', u'获取唯一标识成功', uuids) | |
| 65 | 73 |  | 
| 66 | 74 |  | 
| 67 | 75 | # [How to do a PUT request with curl?](http://stackoverflow.com/questions/13782198/how-to-do-a-put-request-with-curl) | 
| @@ -22,7 +22,9 @@ pep8==1.6.2 | ||
| 22 | 22 | pytz==2015.7 | 
| 23 | 23 | records==0.4.3 | 
| 24 | 24 | redis==2.10.5 | 
| 25 | +redis-extensions==1.0.1 | |
| 25 | 26 | shortuuid==0.4.2 | 
| 26 | 27 | uWSGI==2.0.11.1 | 
| 27 | 28 | versions==0.10.0 | 
| 28 | 29 | wechatpy==1.2.8 | 
| 30 | +https://github.com/Brightcells/django-q/archive/master.zip | 
| @@ -1,5 +1,8 @@ | ||
| 1 | 1 | # -*- coding: utf-8 -*- | 
| 2 | 2 |  | 
| 3 | +# 唯一标识相关 | |
| 4 | +UUID_LIST = 'uuid:list' # List, 唯一标识列表 | |
| 5 | + | |
| 3 | 6 | # 用户相关 | 
| 4 | 7 | PROFILE_INFO = 'profile:info:%s' # STRING,用户信息,user_id | 
| 5 | 8 |  | 
| @@ -0,0 +1,25 @@ | ||
| 1 | +# -*- coding: utf-8 -*- | |
| 2 | + | |
| 3 | +from curtail_uuid import CurtailUUID | |
| 4 | +from django.conf import settings | |
| 5 | + | |
| 6 | +from photo.models import UUIDInfo | |
| 7 | +from utils.redis.rkeys import UUID_LIST | |
| 8 | + | |
| 9 | + | |
| 10 | +r = settings.REDIS_CACHE | |
| 11 | + | |
| 12 | + | |
| 13 | +def generate_uuid(): | |
| 14 | + uuid = CurtailUUID.uuid(UUIDInfo) | |
| 15 | + UUIDInfo.objects.create(uuid=uuid) | |
| 16 | + return uuid | |
| 17 | + | |
| 18 | + | |
| 19 | +def generate_uuids(num=1000): | |
| 20 | + uuids = [generate_uuid() for i in xrange(num)] | |
| 21 | + r.rpush(UUID_LIST, *uuids) | |
| 22 | + | |
| 23 | + | |
| 24 | +def update_uuids(lensman_id, uuids): | |
| 25 | + UUIDInfo.objects.filter(uuid__in=uuids).update(lensman_id=lensman_id, status=False) |