Skip to content

.save() conflicts with TTL on unrelated field #753

@matiasvt

Description

@matiasvt

I found out that if we have a HashModel instance with a field having a TTL and we update another -different- field on that instance then the TTL gets reset but if we use HSET on the field to update then the TTL keeps intact. I'm using redis 8.2 (inside redis cloud) and redis-om 0.3.5.

Is that expected to happen?

e.g. (code snippet at the end) if we have HashModel A with fields x,y,z and have an instance a1 of A with a TTL > 0 on field x and then do something like

a1.y = 3 
a1.save() 

then the ttl of a1.x gets reset/removed and the field does not expire when requested.
But if instead we do
redis.hset(a1.key(), 'y', 3)
then the ttl of field x on a1 remains

class A(HashModel):
    x: str 
    y: int
    z: str

    class Meta:
        database = redis
        model_key_prefix = "AModelExpirationTest"


# Example 1: Using model.save() - TTL gets reset/removed
print("=" * 60)
print("Example 1: Using model.save() - TTL is RESET")
print("=" * 60)


# Create instance and save
a1 = A(x="value_x", y=1, z="value_z")
a1.save()

# Set TTL on field x (10 seconds for demo)
redis.hexpire(a1.key(), 1000, "x")

# Check TTL
ttl = redis.httl(a1.key(), "x")
print(f"Initial TTL on field 'x': {ttl[0]} seconds")

# Modify field y using the model and save
a1.y = 3
a1.save()

# Check TTL again
ttl_after = redis.httl(a1.key(), "x")
print(f"TTL on field 'x' after a1.save(): {ttl_after[0]}")
print(f"TTL was reset: {ttl_after[0] == -1}")  # -1 means no TTL

# Wait and check if field still exists
time.sleep(2)
field_value = redis.hget(a1.key(), "x")
print(f"Field 'x' value after 2 seconds: {field_value}")
print()

# Clean up
redis.delete(a1.key())

# Example 2: Using redis.hset() - TTL is PRESERVED
print("=" * 60)
print("Example 2: Using redis.hset() - TTL is PRESERVED")
print("=" * 60)

# Create new instance
a2 = A(x="value_x", y=1, z="value_z")
a2.save()

# Set TTL on field x (10 seconds for demo)
redis.hexpire(a2.key(), 1000, "x")

# Check TTL
ttl = redis.httl(a2.key(), "x")
print(f"Initial TTL on field 'x': {ttl[0]} seconds")

# Modify field y using direct Redis command
redis.hset(a2.key(), "y", 3)

# Check TTL again
ttl_after = redis.httl(a2.key(), "x")
print(f"TTL on field 'x' after redis.hset(): {ttl_after[0]} seconds")
print(f"TTL was preserved: {ttl_after[0] > 0}")

# Wait and check if field still exists
time.sleep(2)
field_value = redis.hget(a2.key(), "x")
ttl_current = redis.httl(a2.key(), "x")
print(f"Field 'x' value after 2 seconds: {field_value}")
print(f"TTL on field 'x' after 2 seconds: {ttl_current[0]} seconds")
print()

# Clean up
redis.delete(a2.key())

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions