From b730571663c5db1fe9eb471e9d9e461cd1257156 Mon Sep 17 00:00:00 2001 From: Your Name Date: Sun, 19 May 2024 17:14:03 -0400 Subject: [PATCH] cache usage state in api --- common/views.py | 12 ++-------- takahe/apps.py | 4 ++++ takahe/jobs.py | 62 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+), 10 deletions(-) create mode 100644 takahe/jobs.py diff --git a/common/views.py b/common/views.py index 60af379b..ff7ee9f3 100644 --- a/common/views.py +++ b/common/views.py @@ -1,6 +1,7 @@ from django.conf import settings from django.contrib import messages from django.contrib.auth.decorators import login_required +from django.core.cache import cache from django.db import connection from django.http import JsonResponse from django.shortcuts import redirect, render @@ -37,16 +38,7 @@ def ap_redirect(request, uri): def nodeinfo2(request): - usage = {"users": {"total": User.objects.count()}} - # return estimated number of marks as posts, since count the whole table is slow - # TODO filter local with SQL function in https://wiki.postgresql.org/wiki/Count_estimate - with connection.cursor() as cursor: - cursor.execute( - "SELECT n_live_tup FROM pg_stat_all_tables WHERE relname = 'journal_shelflogentry';" - ) - row = cursor.fetchone() - if row: - usage["localPosts"] = row[0] + usage = cache.get("nodeinfo_usage") or {} return JsonResponse( { "version": "2.0", diff --git a/takahe/apps.py b/takahe/apps.py index 7d39fe99..9857a4e5 100644 --- a/takahe/apps.py +++ b/takahe/apps.py @@ -4,3 +4,7 @@ from django.apps import AppConfig class TakaheConfig(AppConfig): default_auto_field = "django.db.models.BigAutoField" name = "takahe" + + def ready(self): + # register cron jobs + from .jobs import TakaheStats # isort:skip diff --git a/takahe/jobs.py b/takahe/jobs.py new file mode 100644 index 00000000..2bc4e4bd --- /dev/null +++ b/takahe/jobs.py @@ -0,0 +1,62 @@ +from datetime import timedelta + +from django.core.cache import cache +from django.db.models import Count, Q +from django.utils import timezone +from loguru import logger + +from common.models import BaseJob, JobManager +from journal.models import Comment, Review, ShelfMember +from mastodon.api import detect_server_info +from mastodon.models import MastodonApplication +from takahe.models import Domain, Identity, Post + + +@JobManager.register +class TakaheStats(BaseJob): + interval = timedelta(hours=6) + max_unreachable_days = 31 + + def active_users(self, d: int) -> int: + return ( + ShelfMember.objects.filter( + created_time__gte=timezone.now() - timedelta(days=d), local=True + ) + .values("owner_id") + .distinct() + .count() + ) + + def run(self): + logger.info("Updating Tahake stats.") + # for /api/v1/instance + stats = { + "user_count": Identity.objects.filter( + local=True, deleted__isnull=True + ).count(), + "status_count": Post.objects.filter(local=True) + .exclude(state__in=["deleted", "deleted_fanned_out"]) + .count(), + "domain_count": Domain.objects.count(), + } + cache.set("instance_info_stats", stats) + # for /api/v2/instance + usage = { + "users": { + "active_month": self.active_users(30), + } + } + cache.set("instance_info_usage", usage) + # for NodeInfo + nodeinfo_usage = { + "users": { + "total": stats["user_count"], + "activeHalfyear": usage["users"]["active_month"], + "activeMonth": self.active_users(180), + }, + "localPosts": ShelfMember.objects.filter(local=True).count(), + "localComments": Comment.objects.filter(local=True).count() + + Review.objects.filter(local=True).count(), + } + cache.set("nodeinfo_usage", nodeinfo_usage) + logger.info(f"Tahake stats updated. {stats} {nodeinfo_usage}")