Skip to content

Commit

Permalink
add expire cache entries (#120)
Browse files Browse the repository at this point in the history
  • Loading branch information
malmans2 authored Jul 23, 2024
1 parent 4b6e573 commit bfa6a94
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 1 deletion.
8 changes: 7 additions & 1 deletion cacholote/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,12 @@

from . import config, database, extra_encoders, utils
from .cache import cacheable
from .clean import clean_cache_files, clean_invalid_cache_entries, delete
from .clean import (
clean_cache_files,
clean_invalid_cache_entries,
delete,
expire_cache_entries,
)
from .decode import loads
from .encode import dumps

Expand All @@ -40,6 +45,7 @@
"database",
"delete",
"dumps",
"expire_cache_entries",
"extra_encoders",
"loads",
"utils",
Expand Down
24 changes: 24 additions & 0 deletions cacholote/clean.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import pydantic
import sqlalchemy as sa
import sqlalchemy.orm
from sqlalchemy import BinaryExpression, ColumnElement

from . import config, database, decode, encode, extra_encoders, utils

Expand Down Expand Up @@ -354,3 +355,26 @@ def clean_invalid_cache_entries(
decode.loads(cache_entry._result_as_string)
except decode.DecodeError:
_delete_cache_entry(session, cache_entry)


def expire_cache_entries(
tags: list[str] | None = None,
before: datetime.datetime | None = None,
after: datetime.date | None = None,
) -> None:
now = utils.utcnow()

filters: list[BinaryExpression[bool] | ColumnElement[bool]] = []
if tags is not None:
filters.append(database.CacheEntry.tag.in_(tags))
if before is not None:
filters.append(database.CacheEntry.timestamp < before)
if after is not None:
filters.append(database.CacheEntry.timestamp > after)

with config.get().instantiated_sessionmaker() as session:
for cache_entry in session.scalars(
sa.select(database.CacheEntry).filter(*filters)
):
cache_entry.expiration = now
database._commit_or_rollback(session)
34 changes: 34 additions & 0 deletions tests/test_60_clean.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
from cacholote import cache, clean, config, utils

ONE_BYTE = os.urandom(1)
TODAY = datetime.datetime.now(tz=datetime.timezone.utc)
TOMORROW = TODAY + datetime.timedelta(days=1)
YESTERDAY = TODAY - datetime.timedelta(days=1)
does_not_raise = contextlib.nullcontext


Expand All @@ -30,6 +33,11 @@ def open_urls(*urls: pathlib.Path) -> list[fsspec.spec.AbstractBufferedFile]:
return [fsspec.open(url).open() for url in urls]


@cache.cacheable
def cached_now() -> datetime.datetime:
return datetime.datetime.now()


@pytest.mark.parametrize("method", ["LRU", "LFU"])
@pytest.mark.parametrize("set_cache", ["file", "cads"], indirect=True)
def test_clean_cache_files(
Expand Down Expand Up @@ -301,3 +309,29 @@ def test_clean_multiple_files(tmp_path: pathlib.Path) -> None:

clean.clean_cache_files(0)
assert len(fs.ls(dirname)) == 0


@pytest.mark.parametrize(
"tags,before,after",
[
(["foo"], None, None),
(None, TOMORROW, None),
(None, None, YESTERDAY),
(["foo"], TOMORROW, YESTERDAY),
],
)
def test_expire_cache_entries(
tags: None | list[str],
before: None | datetime.datetime,
after: None | datetime.datetime,
) -> None:
with config.set(tag="foo"):
now = cached_now()

# Do not expire
clean.expire_cache_entries(tags=["bar"], before=YESTERDAY, after=TOMORROW)
assert now == cached_now()

# Expire
clean.expire_cache_entries(tags=tags, before=before, after=after)
assert now != cached_now()

0 comments on commit bfa6a94

Please sign in to comment.