MukeshKapoor25's picture
feat(dashboard): implement 3-tier caching architecture for mobile performance
fd7ec1d
"""
Dashboard utility functions for cache management and updates.
Call these functions when transactions/bookings/wallet changes occur.
"""
from insightfy_utils.logging import get_logger
from app.cache import get_redis
logger = get_logger(__name__)
async def update_dashboard_on_transaction(
partner_id: str,
transaction_type: str = "transaction"
) -> bool:
"""
Update dashboard summary when a transaction occurs.
This is the main function to call after order/wallet/booking changes.
Flow:
1. Invalidate Redis cache
2. Fetch fresh data from database
3. Update MongoDB spa_dashboard_summary collection
4. Redis will be populated from MongoDB on next API request
Args:
partner_id: Partner ID
transaction_type: Type of transaction (order, wallet, booking, etc.)
Returns:
bool: True if successful
Usage:
# After creating order
await update_dashboard_on_transaction(partner_id, "order_created")
# After wallet transaction
await update_dashboard_on_transaction(partner_id, "wallet_transaction")
# After booking update
await update_dashboard_on_transaction(partner_id, "booking_updated")
"""
try:
# Step 1: Invalidate Redis cache
await invalidate_redis_cache(partner_id)
# Step 2 & 3: Fetch from database and update MongoDB
from app.dashboard.services.mongo_persistence import dashboard_mongo
from app.dashboard.services.service import DashboardService
# Fetch fresh data
summary = await DashboardService._fetch_from_database(partner_id)
# Update MongoDB
summary_data = summary.model_dump(mode='json')
success = await dashboard_mongo.upsert_summary(
partner_id,
summary_data,
transaction_type=transaction_type
)
if success:
logger.info(
"Dashboard updated on transaction",
extra={
"partner_id": partner_id,
"transaction_type": transaction_type
}
)
return success
except Exception as e:
logger.error(
"Error updating dashboard on transaction",
exc_info=e,
extra={
"partner_id": partner_id,
"transaction_type": transaction_type
}
)
return False
async def invalidate_redis_cache(partner_id: str) -> bool:
"""
Invalidate Redis cache for a specific partner.
Args:
partner_id: Partner ID
Returns:
bool: True if cache was invalidated
"""
try:
redis_client = get_redis()
if not redis_client:
logger.warning("Redis client not available")
return False
cache_key = f"dashboard:summary:{partner_id}"
deleted = await redis_client.delete(cache_key)
if deleted:
logger.debug(
"Redis cache invalidated",
extra={"partner_id": partner_id}
)
return bool(deleted)
except Exception as e:
logger.error(
"Error invalidating Redis cache",
exc_info=e,
extra={"partner_id": partner_id}
)
return False
async def invalidate_mongo_cache(partner_id: str) -> bool:
"""
Delete dashboard summary from MongoDB.
Use this only when you want to completely remove cached data.
Args:
partner_id: Partner ID
Returns:
bool: True if deleted
"""
try:
from app.dashboard.services.mongo_persistence import dashboard_mongo
success = await dashboard_mongo.delete_summary(partner_id)
if success:
logger.info(
"MongoDB cache deleted",
extra={"partner_id": partner_id}
)
return success
except Exception as e:
logger.error(
"Error deleting MongoDB cache",
exc_info=e,
extra={"partner_id": partner_id}
)
return False
async def invalidate_all_caches(partner_id: str) -> bool:
"""
Invalidate both Redis and MongoDB caches.
Args:
partner_id: Partner ID
Returns:
bool: True if both were invalidated
"""
try:
redis_result = await invalidate_redis_cache(partner_id)
mongo_result = await invalidate_mongo_cache(partner_id)
return redis_result and mongo_result
except Exception as e:
logger.error(
"Error invalidating all caches",
exc_info=e,
extra={"partner_id": partner_id}
)
return False
async def bulk_update_dashboards(
partner_ids: list[str],
transaction_type: str = "bulk_update"
) -> dict:
"""
Bulk update dashboard summaries for multiple partners.
Useful for batch operations or background jobs.
Args:
partner_ids: List of partner IDs
transaction_type: Type of transaction
Returns:
dict: Results with success/failure counts
"""
results = {
"total": len(partner_ids),
"success": 0,
"failed": 0,
"errors": []
}
for partner_id in partner_ids:
try:
success = await update_dashboard_on_transaction(
partner_id,
transaction_type
)
if success:
results["success"] += 1
else:
results["failed"] += 1
except Exception as e:
results["failed"] += 1
results["errors"].append({
"partner_id": partner_id,
"error": str(e)
})
logger.info(
"Bulk dashboard update completed",
extra=results
)
return results
# Convenience functions for specific transaction types
async def update_on_order_created(partner_id: str) -> bool:
"""Update dashboard when order is created"""
return await update_dashboard_on_transaction(partner_id, "order_created")
async def update_on_order_status_changed(partner_id: str) -> bool:
"""Update dashboard when order status changes"""
return await update_dashboard_on_transaction(partner_id, "order_status_changed")
async def update_on_wallet_transaction(partner_id: str) -> bool:
"""Update dashboard when wallet transaction occurs"""
return await update_dashboard_on_transaction(partner_id, "wallet_transaction")
async def update_on_payment_received(partner_id: str) -> bool:
"""Update dashboard when payment is received"""
return await update_dashboard_on_transaction(partner_id, "payment_received")
async def update_on_rating_submitted(partner_id: str) -> bool:
"""Update dashboard when rating is submitted"""
return await update_dashboard_on_transaction(partner_id, "rating_submitted")