优化下载次数统计,放到缓存里面,每10秒同步到数据库

super_signature
nineven 5 years ago
parent 5f7873c29f
commit a8b5d4dbbe
  1. 2
      fir_ser/api/models.py
  2. 52
      fir_ser/api/utils/crontab/run.py
  3. 20
      fir_ser/api/utils/crontab/sync_cache.py
  4. 4
      fir_ser/api/utils/serializer.py
  5. 47
      fir_ser/api/utils/storage/caches.py
  6. 44
      fir_ser/api/views/download.py
  7. 8
      fir_ser/fir_ser/settings.py
  8. 3
      fir_ser/requirements.txt

@ -59,7 +59,7 @@ class Token(models.Model):
""" """
The default authorization token model. The default authorization token model.
""" """
access_token = models.CharField(max_length=42, unique=True) access_token = models.CharField(max_length=64, unique=True)
user = models.ForeignKey( user = models.ForeignKey(
UserInfo, related_name='auth_token', UserInfo, related_name='auth_token',
on_delete=models.CASCADE, verbose_name="关联用户" on_delete=models.CASCADE, verbose_name="关联用户"

@ -0,0 +1,52 @@
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# project: 4月
# author: liuyu
# date: 2020/4/7
from apscheduler.schedulers.background import BackgroundScheduler
from django_apscheduler.jobstores import DjangoJobStore, register_events, register_job
from api.utils.crontab.sync_cache import sync_download_times
import atexit
import fcntl
# 主要是为了防止多进程出现的多个定时任务同时执行
f = open("scheduler.lock", "wb")
try:
fcntl.flock(f, fcntl.LOCK_EX | fcntl.LOCK_NB)
# 开启定时工作
try:
# 实例化调度器
scheduler = BackgroundScheduler()
# 调度器使用DjangoJobStore()
scheduler.add_jobstore(DjangoJobStore(), "default")
# 设置定时任务,选择方式为interval,时间间隔为10s
# 另一种方式为每天固定时间执行任务,对应代码为:
# @register_job(scheduler, 'cron', day_of_week='mon-fri', hour='9', minute='30', second='10',id='task_time')
@register_job(scheduler, "interval", seconds=10)
def sync_download_times_job():
# 这里写你要执行的任务
sync_download_times()
register_events(scheduler)
scheduler.start()
except Exception as e:
print(e)
# 有错误就停止定时器
scheduler.shutdown()
except:
pass
def unlock():
fcntl.flock(f, fcntl.LOCK_UN)
f.close()
atexit.register(unlock)

@ -0,0 +1,20 @@
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# project: 4月
# author: liuyu
# date: 2020/4/7
from api.models import Apps
from django.core.cache import cache
from fir_ser.settings import CACHE_KEY_TEMPLATE
def sync_download_times():
down_tem_key = CACHE_KEY_TEMPLATE.get("download_times_key")
key = "%s%s" %(down_tem_key,'*')
for app_download in cache.iter_keys(key):
app_id = app_download.split(down_tem_key)[1]
Apps.objects.filter(app_id=app_id).update(count_hits=cache.get(app_download))

@ -46,7 +46,7 @@ class AppsSerializer(serializers.ModelSerializer):
if self.context.get("storage", None) and self.context.get("storage") != "undefined": if self.context.get("storage", None) and self.context.get("storage") != "undefined":
storage = self.context.get("storage", None) storage = self.context.get("storage", None)
icon_url = storage.get_download_url(os.path.basename(master_release_obj.icon_url),300) icon_url = storage.get_download_url(os.path.basename(master_release_obj.icon_url),600)
datainfo = { datainfo = {
"app_version": master_release_obj.app_version, "app_version": master_release_obj.app_version,
"icon_url": icon_url, "icon_url": icon_url,
@ -60,7 +60,7 @@ class AppsSerializer(serializers.ModelSerializer):
"binary_url":master_release_obj.binary_url, "binary_url":master_release_obj.binary_url,
} }
download_token = token_obj.make_token(master_release_obj.release_id,300) download_token = token_obj.make_token(master_release_obj.release_id,600)
datainfo["download_token"] = download_token datainfo["download_token"] = download_token
return datainfo return datainfo

@ -0,0 +1,47 @@
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# project: 4月
# author: liuyu
# date: 2020/4/7
from django.core.cache import cache
from api.models import Apps,UserInfo
import time
from fir_ser.settings import CACHE_KEY_TEMPLATE
from api.utils.storage.storage import Storage,LocalStorage
from api.utils.crontab import run
def get_download_url_by_cache(app_obj, filename, limit, isdownload=False):
now = time.time()
download_val = cache.get("%s_%s" % ('download_url', filename))
if download_val:
if download_val.get("time") > now - 60:
return download_val.get("download_url")
else:
if isdownload:
local_storage = LocalStorage('localhost', False)
return local_storage.get_download_url(filename, limit, 'plist')
user_obj = UserInfo.objects.filter(pk=app_obj.get("user_id")).first()
storage = Storage(user_obj)
return storage.get_download_url(filename, limit)
def get_app_instance_by_cache(app_id, limit):
app_obj_cache = cache.get("%s_%s" % ('app_instance', app_id))
if not app_obj_cache:
app_obj_cache = Apps.objects.filter(app_id=app_id).values("pk", 'user_id', 'type').first()
cache.set("%s_%s" % ('app_instance', app_id), app_obj_cache, limit)
return app_obj_cache
def get_app_download_by_cache(app_id):
down_tem_key = CACHE_KEY_TEMPLATE.get("download_times_key")
key = "%s%s" %(down_tem_key,app_id)
download_times = cache.get(key)
if not download_times:
download_times=Apps.objects.filter(app_id=app_id).values("count_hits").first().get('count_hits')
cache.set(key, download_times + 1, 900)
else:
cache.incr(key)
return download_times + 1

@ -10,13 +10,13 @@ from fir_ser import settings
from api.utils.TokenManager import DownloadToken from api.utils.TokenManager import DownloadToken
from api.utils.app.randomstrings import make_random_uuid from api.utils.app.randomstrings import make_random_uuid
from api.utils.app.apputils import make_resigned from api.utils.app.apputils import make_resigned
from api.utils.storage.storage import Storage,LocalStorage from api.utils.storage.storage import Storage
import os,time from api.utils.storage.caches import get_app_instance_by_cache,get_download_url_by_cache,get_app_download_by_cache
from django.core.cache import cache import os
from rest_framework_extensions.cache.decorators import cache_response from rest_framework_extensions.cache.decorators import cache_response
from api.utils.serializer import AppsSerializer from api.utils.serializer import AppsSerializer
from api.models import Apps,AppReleaseInfo,UserInfo from api.models import Apps,AppReleaseInfo
from django.db.models import F from django.db.models import F
from django.http import FileResponse from django.http import FileResponse
class DownloadView(APIView): class DownloadView(APIView):
@ -72,7 +72,7 @@ class ShortDownloadView(APIView):
根据下载短链接获取应用信息 根据下载短链接获取应用信息
''' '''
@cache_response(timeout=300-60, cache="default",key_func='calculate_cache_key',cache_errors=False) @cache_response(timeout=600-60, cache="default",key_func='calculate_cache_key',cache_errors=False)
def get(self,request,short): def get(self,request,short):
res = BaseResponse() res = BaseResponse()
release_id = request.query_params.get("release_id", None) release_id = request.query_params.get("release_id", None)
@ -118,23 +118,23 @@ class InstallView(APIView):
dtoken = DownloadToken() dtoken = DownloadToken()
if dtoken.verify_token(downtoken,release_id): if dtoken.verify_token(downtoken,release_id):
# app_obj = Apps.objects.filter(app_id=app_id).values("pk",'user_id','type','short').first() # app_obj = Apps.objects.filter(app_id=app_id).values("pk",'user_id','type','short').first()
app_obj = self.get_app_instance_by_cache(app_id,900) app_obj = get_app_instance_by_cache(app_id,900)
if app_obj: if app_obj:
Apps.objects.filter(app_id=app_id).update(count_hits=F('count_hits') + 1) # Apps.objects.filter(app_id=app_id).update(count_hits=F('count_hits') + 1)
UserInfo.objects.filter(pk=app_obj.get("user_id")).update(all_download_times=F('all_download_times') + 1) # UserInfo.objects.filter(pk=app_obj.get("user_id")).update(all_download_times=F('all_download_times') + 1)
get_app_download_by_cache(app_id)
# release_obj = AppReleaseInfo.objects.filter(app_id=app_obj.get('pk')).values("release_id") # release_obj = AppReleaseInfo.objects.filter(app_id=app_obj.get('pk')).values("release_id")
# if release_obj: # if release_obj:
if app_obj.get("type") == 0: if app_obj.get("type") == 0:
apptype = '.apk' apptype = '.apk'
download_url = self.get_download_url_by_cache(app_obj,release_id + apptype,600) download_url = get_download_url_by_cache(app_obj,release_id + apptype,600)
else: else:
apptype = '.ipa' apptype = '.ipa'
if isdownload : if isdownload :
download_url = self.get_download_url_by_cache(app_obj,release_id + apptype, 600) download_url = get_download_url_by_cache(app_obj,release_id + apptype, 600)
else: else:
download_url = self.get_download_url_by_cache(app_obj,release_id + apptype,600,isdownload) download_url = get_download_url_by_cache(app_obj,release_id + apptype,600,isdownload)
res.data={"download_url":download_url} res.data={"download_url":download_url}
return Response(res.dict) return Response(res.dict)
@ -147,23 +147,3 @@ class InstallView(APIView):
res.msg = "该应用不存在" res.msg = "该应用不存在"
return Response(res.dict) return Response(res.dict)
def get_download_url_by_cache(self,app_obj,filename,limit,isdownload=False):
now = time.time()
download_val = cache.get("%s_%s" % ('download_url', filename))
if download_val:
if download_val.get("time") > now - 60:
return download_val.get("download_url")
else:
if isdownload:
local_storage = LocalStorage('localhost', False)
return local_storage.get_download_url(filename, limit, 'plist')
user_obj = UserInfo.objects.filter(pk=app_obj.get("user_id")).first()
storage = Storage(user_obj)
return storage.get_download_url(filename, limit)
def get_app_instance_by_cache(self,app_id,limit):
app_obj_cache = cache.get("%s_%s" % ('app_instance', app_id))
if not app_obj_cache:
app_obj_cache = Apps.objects.filter(app_id=app_id).values("pk",'user_id','type').first()
cache.set("%s_%s" % ('app_instance', app_id),app_obj_cache,limit)
return app_obj_cache

@ -38,6 +38,7 @@ INSTALLED_APPS = [
'django.contrib.messages', 'django.contrib.messages',
'django.contrib.staticfiles', 'django.contrib.staticfiles',
'api.apps.ApiConfig', 'api.apps.ApiConfig',
'django_apscheduler',#定时执行任务
'rest_framework', 'rest_framework',
] ]
@ -231,3 +232,10 @@ THIRD_PART_CONFIG = {
] ]
} }
CACHE_KEY_TEMPLATE={
'download_times_key':'app_download_times_'
}
SESSION_ENGINE = "django.contrib.sessions.backends.cache"
SESSION_CACHE_ALIAS = "default"

@ -3,6 +3,7 @@ aliyun-python-sdk-core-v3==2.13.11
aliyun-python-sdk-kms==2.10.1 aliyun-python-sdk-kms==2.10.1
aliyun-python-sdk-sts==3.0.1 aliyun-python-sdk-sts==3.0.1
androguard==3.3.5 androguard==3.3.5
APScheduler==3.6.3
asgiref==3.2.3 asgiref==3.2.3
asn1crypto==1.3.0 asn1crypto==1.3.0
backcall==0.1.0 backcall==0.1.0
@ -14,6 +15,7 @@ crcmod==1.7
cycler==0.10.0 cycler==0.10.0
decorator==4.4.2 decorator==4.4.2
Django==3.0.3 Django==3.0.3
django-apscheduler==0.3.0
django-qrcode==0.3 django-qrcode==0.3
django-redis==4.11.0 django-redis==4.11.0
django-rest-framework==0.1.0 django-rest-framework==0.1.0
@ -52,6 +54,7 @@ requests==2.23.0
six==1.14.0 six==1.14.0
sqlparse==0.3.1 sqlparse==0.3.1
traitlets==4.3.3 traitlets==4.3.3
tzlocal==2.0.0
urllib3==1.25.8 urllib3==1.25.8
uWSGI==2.0.18 uWSGI==2.0.18
wcwidth==0.1.8 wcwidth==0.1.8

Loading…
Cancel
Save