Skip to content

Commit

Permalink
refactor to use safe cache operations
Browse files Browse the repository at this point in the history
  • Loading branch information
kelvin-muchiri committed Nov 8, 2024
1 parent 2754d25 commit 0df1bed
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 9 deletions.
22 changes: 13 additions & 9 deletions onadata/libs/renderers/renderers.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,18 @@
"""
Custom renderers for use with django rest_framework.
"""

import decimal
import json
import math
from io import BytesIO, StringIO
from typing import Tuple

from django.core.cache import cache
from django.utils import timezone
from django.utils.dateparse import parse_datetime
from django.utils.encoding import force_str, smart_str
from django.utils.xmlutils import SimplerXMLGenerator


import six
from rest_framework import negotiation
from rest_framework.renderers import (
Expand All @@ -28,12 +27,15 @@
from six import iteritems

from onadata.libs.utils.cache_tools import (
XFORM_MANIFEST_CACHE_TTL,
XFORM_MANIFEST_CACHE_LOCK_TTL,
XFORM_MANIFEST_CACHE_TTL,
safe_cache_add,
safe_cache_get,
safe_cache_set,
safe_delete,
)
from onadata.libs.utils.osm import get_combined_osm


IGNORE_FIELDS = [
"formhub/uuid",
"meta/contactID",
Expand Down Expand Up @@ -395,18 +397,20 @@ def _get_current_buffer_data(self):

if data and self.can_update_cache:
data = data.strip()
cached_manifest: str | None = cache.get(self.cache_key)
cached_manifest: str | None = safe_cache_get(self.cache_key)

if cached_manifest is not None:
cached_manifest += data
cache.set(self.cache_key, cached_manifest, XFORM_MANIFEST_CACHE_TTL)
safe_cache_set(
self.cache_key, cached_manifest, XFORM_MANIFEST_CACHE_TTL
)

if data.endswith("</manifest>"):
# We are done, release the lock
cache.delete(self.cache_lock_key)
safe_delete(self.cache_lock_key)

else:
cache.set(self.cache_key, data, XFORM_MANIFEST_CACHE_TTL)
safe_cache_set(self.cache_key, data, XFORM_MANIFEST_CACHE_TTL)

return data

Expand All @@ -415,7 +419,7 @@ def stream_data(self, data, serializer):
# In the case of concurrent requests, we ensure only the first
# request is updating the cache
self.cache_lock_key = f"{self.cache_key}_lock"
self.can_update_cache = cache.add(
self.can_update_cache = safe_cache_add(
self.cache_lock_key, "true", XFORM_MANIFEST_CACHE_LOCK_TTL
)

Expand Down
27 changes: 27 additions & 0 deletions onadata/libs/utils/cache_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,33 @@ def safe_cache_get(key, default=None):
return default


def safe_cache_add(key, value, timeout=None):
"""
Safely add a value to the cache.
If the cache is not reachable, the operation silently fails.
Args:
key (str): The cache key to add.
value (Any): The value to store in the cache.
timeout (int, optional): The cache timeout in seconds. If None,
the default cache timeout will be used.
Returns:
bool: True if the value was added to the cache, False otherwise.
"""
try:
return cache.add(key, value, timeout)
except ConnectionError as exc:
# Handle cache connection error
logger.exception(exc)
return False
except socket.error as exc:
# Handle other potential connection errors, especially for
# older Python versions
logger.exception(exc)
return False


class CacheLockError(Exception):
"""Custom exception raised when a cache lock cannot be acquired."""

Expand Down

0 comments on commit 0df1bed

Please sign in to comment.