Files
SMANAGE/gvsds/apps/stats/tasks.py
T
TermiNexus 31b0ab885f refactor(orm): 手写 ORM 下沉 gvsdsdk Manager,通用工具改为 SDK 转发
P1 通用查询:viewsets / app / menu / mail / gitea / mc / stats / sync_apps 等视图与命令的裸查询改委托 SDK Manager(Role/Company/Department/Position/Menu/Tenant/App)。

P2 App 体系:app_manager.py 与 app_manifests.py 实现零裸 ORM,职务多值/虚拟职务/公司下拉全部走 SDK。

P3 工具下沉:money/json_encoder/celery_utils/exception_handler/redis_lock 改为纯转发展开;ip_filter/storage 转发并注入 app.ini 配置源;common 下 DateTime/String/Naming/UUID 转发 SDK。

删除死代码 commission/strategies/engine.py(SDK 已有同物且零引用)与 payment/models.py 的 FromTenantAndPlatform;单测 patch 目标同步为 gvsdsdk.*,test_attack_detect fixture 补齐限频去重状态。
2026-09-13 21:58:06 +08:00

108 lines
4.1 KiB
Python

"""模块:统计引擎 Celery 任务
将统计引擎的定时清零、过期清理、排行榜生成接入 Celery beat 调度。
通过 gvsds/celery.py 的 beat_schedule 配置定时触发。
无 Celery 时可通过 management 命令或外部 cron 手动调用。
统一走 gvsdsdk StatsManager 编排方法,避免双轨实现。
"""
import logging
from datetime import date, timedelta
from celery import shared_task
from gvsds.celery_utils import RetryOnFailure
logger = logging.getLogger(__name__)
#: PurgeOld 清理的周期类型(daily 每日 / monthly 每月 / hourly 每小时)
_PURGE_PERIOD_TYPES = ('daily', 'monthly', 'hourly')
@shared_task(bind=True, name='stats.ResetDailyStats')
@RetryOnFailure(max_retries=2, delay=5)
def ResetDailyStats(self):
"""每日统计清零任务——重置所有租户的 daily 周期数据(默认清零昨天)。
建议 beat 调度:每日 00:00 执行。
"""
from gvsdsdk.stats.manager import StatsManager
total = 0
for tenant_uuid in _GetActiveTenants():
try:
total += StatsManager.RunScheduledResets(tenant_uuid)
except Exception:
logger.warning('[StatsTasks] ResetDaily 失败: tenant=%s', tenant_uuid, exc_info=True)
logger.info('[StatsTasks] ResetDailyStats 完成,重置 %d 条', total)
return {'reset_count': total}
@shared_task(bind=True, name='stats.ResetMonthlyStats')
@RetryOnFailure(max_retries=2, delay=5)
def ResetMonthlyStats(self):
"""每月统计清零任务——重置所有租户的 monthly 周期数据(默认清零上月)。
建议 beat 调度:每月 1 日 00:00 执行。
"""
from gvsdsdk.stats.manager import StatsManager
total = 0
for tenant_uuid in _GetActiveTenants():
for config in StatsManager.ListAutoResetConfigs(tenant_uuid):
try:
total += StatsManager.MonthlyReset(tenant_uuid, config.Metric_id)
except Exception:
logger.warning('[StatsTasks] ResetMonthly 失败: tenant=%s metric=%s', tenant_uuid, config.Metric_id, exc_info=True)
logger.info('[StatsTasks] ResetMonthlyStats 完成,重置 %d 条', total)
return {'reset_count': total}
@shared_task(bind=True, name='stats.PurgeOldStats')
def PurgeOldStats(self, retention_days=90):
"""清理过期统计数据——删除 N 天前的 daily 记录。
建议 beat 调度:每日 03:00 执行(避开清零高峰)。
"""
from gvsdsdk.stats.manager import StatsManager
before = date.today() - timedelta(days=retention_days)
total = 0
for tenant_uuid in _GetActiveTenants():
try:
total += StatsManager.PurgeOld(tenant_uuid, before, period_type='daily')
except Exception:
logger.warning('[StatsTasks] PurgeOld 失败: tenant=%s', tenant_uuid, exc_info=True)
logger.info('[StatsTasks] PurgeOldStats 完成,清理 %d 条(保留 %d 天)', total, retention_days)
return {'purge_count': total, 'before_date': before.isoformat()}
@shared_task(bind=True, name='stats.BuildDailyRankings')
@RetryOnFailure(max_retries=2, delay=5)
def BuildDailyRankings(self):
"""生成每日排行榜——为所有启用排行的指标生成当日排行。
建议 beat 调度:每日 23:50 执行(当日数据基本定型)。
"""
from gvsdsdk.stats.manager import StatsManager
total = 0
for tenant_uuid in _GetActiveTenants():
try:
total += StatsManager.BuildRankings(tenant_uuid)
except Exception:
logger.warning('[StatsTasks] BuildRanking 失败: tenant=%s', tenant_uuid, exc_info=True)
logger.info('[StatsTasks] BuildDailyRankings 完成,生成 %d 个排行', total)
return {'ranking_count': total}
def _GetActiveTenants():
"""获取所有活跃租户的 UUID 列表(bytes 形式,委托 SDK TenantManager)。"""
try:
from gvsdsdk.auth.managers import TenantManager
return TenantManager.ListActiveTenants()
except Exception:
logger.warning('[StatsTasks] 获取租户列表失败,返回空列表', exc_info=True)
return []