Skip to content

How to define custom serializers / unserializers?

Introduction

All values stored in the cache (with low-level API or with high-level decorators) are serialized into bytes before being stored in redis.

By default, with use the standard pickle module to serialize/unserialize.

But you may want to override this default setting:

  • to compress the data inside the cache
  • to avoid the serialization/unserialization process overhead (if you store only bytes in the cache)
  • ...

How to compress the data inside the cache

import pickle
import zlib
from typing import Any

from rtc import RedisTaggedCache


def custom_serializer(value: Any) -> bytes:
    """Custom serializer is a simple function to convert any value to bytes.

    If an exception is raised here, a warning will be logged
    and the cache will be bypassed.

    """
    serialized = pickle.dumps(value)  # serialize the value
    return zlib.compress(serialized)  # compress the serialized value


def custom_unserializer(value: bytes) -> Any:
    """Custom unserializer is a simple function to convert bytes to a value.

    If an exception is raised here, a warning will be logged
    and the cache will be bypassed.

    """
    serialized = zlib.decompress(value)  # decompress the value
    return pickle.loads(serialized)  # unserialize the value


cache = RedisTaggedCache(
    namespace="foo",
    host="localhost",
    port=6379,
    serializer=custom_serializer,
    unserializer=custom_unserializer,
)

# Use cache normally
value = ["data", "to", "store"]
cache.set("key1", value, tags=["tag1", "tag2"])

How to bypass the serialization

Warning to the high level decorators!

If you are sure to use only bytes as values in the cache low-level API, be careful about the high-level decorators that automatically cache the returned value of functions/methods. In that particular case, they also have to return bytes!

from typing import Any

from rtc import RedisTaggedCache


def custom_serializer(value: Any) -> bytes:
    """Custom serializer is a simple function to convert any value to bytes.

    Here, we consider that value is already bytes.

    If an exception is raised here, a warning will be logged
    and the cache will be bypassed.

    """
    try:
        value.decode()
    except (AttributeError, UnicodeDecodeError):
        raise TypeError("The value must be bytes")
    # value is bytes
    return value  # type: ignore


cache = RedisTaggedCache(
    namespace="foo",
    host="localhost",
    port=6379,
    serializer=custom_serializer,
    unserializer=lambda x: x,  # we don't need any transformation in that particular case
)

# Use cache normally
value_as_bytes = b"foo"
cache.set("key1", value_as_bytes, tags=["tag1", "tag2"])