From 80f1c90fbae764c3056984a1b4802f4b9f8fd1c4 Mon Sep 17 00:00:00 2001 From: Romain Dorgueil Date: Thu, 31 Oct 2024 16:59:06 +0100 Subject: [PATCH] fix: force store metadata to avoid cache bug --- docs/contribute/release/sources.rst | 16 ++++++++++++++++ .../http_client/contrib/hishel/adapters.py | 4 ++-- .../storage/services/blob_storages/memory.py | 2 ++ .../storage/services/blob_storages/null.py | 5 +++++ .../storage/services/blob_storages/redis.py | 2 ++ harp_apps/storage/services/blob_storages/sql.py | 17 ++++++++++++++++- harp_apps/storage/types/blob_storage.py | 2 ++ 7 files changed, 45 insertions(+), 3 deletions(-) diff --git a/docs/contribute/release/sources.rst b/docs/contribute/release/sources.rst index 3c68967e..ac2a8739 100644 --- a/docs/contribute/release/sources.rst +++ b/docs/contribute/release/sources.rst @@ -97,3 +97,19 @@ Eventually forward-port the new version ::::::::::::::::::::::::::::::::::::::: If a newer version line is available, checkout and merge the new version into it. + + +Create the GitHub release +::::::::::::::::::::::::: + +.. code:: shell + + open https://github.com/msqd/harp/releases/tag/$VERSION + +Create the release from tag (button on the right). + +To generate the markdown changes for github, use: + +.. code-block:: shell + + pandoc -s -o docs/changelogs/$VERSION.rst changes.md diff --git a/harp_apps/http_client/contrib/hishel/adapters.py b/harp_apps/http_client/contrib/hishel/adapters.py index 3aa4bd2e..a1f3e156 100644 --- a/harp_apps/http_client/contrib/hishel/adapters.py +++ b/harp_apps/http_client/contrib/hishel/adapters.py @@ -106,7 +106,7 @@ async def _store_cache_meta( # with hishel's current design, it's the only decent way to make it work that we found. Maybe we want to change # the key-value store in the future to be able to contain content addressable and unadressable data, even maybe # namespaced/typed data (although we hack "content-type to do it, for now). - return await self.storage.put( + return await self.storage.force_put( Blob( id=key, data=yaml.safe_dump( @@ -122,7 +122,7 @@ async def _store_cache_meta( sort_keys=False, ).encode(), content_type="cache/meta", - ) + ), ) async def _serialize_request(self, request: Request) -> SerializedRequest: diff --git a/harp_apps/storage/services/blob_storages/memory.py b/harp_apps/storage/services/blob_storages/memory.py index 512514c3..7506e6f2 100644 --- a/harp_apps/storage/services/blob_storages/memory.py +++ b/harp_apps/storage/services/blob_storages/memory.py @@ -16,6 +16,8 @@ async def put(self, blob: Blob) -> Blob: self._blobs[blob.id] = blob return blob + force_put = put + async def delete(self, blob_id: str): del self._blobs[blob_id] diff --git a/harp_apps/storage/services/blob_storages/null.py b/harp_apps/storage/services/blob_storages/null.py index 2579351b..9e8d2781 100644 --- a/harp_apps/storage/services/blob_storages/null.py +++ b/harp_apps/storage/services/blob_storages/null.py @@ -1,3 +1,5 @@ +from typing import override + from harp.models import Blob from harp_apps.storage.types import IBlobStorage @@ -8,9 +10,12 @@ class NullBlobStorage(IBlobStorage): async def get(self, blob_id: str): return None + @override async def put(self, blob: Blob) -> Blob: return blob + force_put = put + async def delete(self, blob_id: str): pass diff --git a/harp_apps/storage/services/blob_storages/redis.py b/harp_apps/storage/services/blob_storages/redis.py index bdb2171a..cb67196e 100644 --- a/harp_apps/storage/services/blob_storages/redis.py +++ b/harp_apps/storage/services/blob_storages/redis.py @@ -28,6 +28,8 @@ async def put(self, blob: Blob) -> Blob: await self.client.set(blob.id, ((blob.content_type or "") + "\n").encode() + blob.data) return blob + force_put = put + @override async def delete(self, blob_id): await self.client.delete(blob_id) diff --git a/harp_apps/storage/services/blob_storages/sql.py b/harp_apps/storage/services/blob_storages/sql.py index f5de3221..f0d8a421 100644 --- a/harp_apps/storage/services/blob_storages/sql.py +++ b/harp_apps/storage/services/blob_storages/sql.py @@ -1,7 +1,7 @@ from collections import OrderedDict from typing import override -from sqlalchemy import delete, insert, select +from sqlalchemy import delete, insert, select, update from sqlalchemy.exc import IntegrityError from sqlalchemy.ext.asyncio import AsyncEngine @@ -96,6 +96,21 @@ async def put(self, blob: Blob) -> Blob: pass # already there? that's fine! return blob + @override + async def force_put(self, blob: Blob) -> Blob: + async with self.engine.connect() as conn: + try: + await conn.execute( + insert(SqlBlob).values(id=blob.id, data=blob.data, content_type=blob.content_type), + ) + await conn.commit() + except IntegrityError: + await conn.execute( + update(SqlBlob).where(SqlBlob.id == blob.id).values(data=blob.data, content_type=blob.content_type), + ) + await conn.commit() + return blob + @override async def delete(self, blob_id): """ diff --git a/harp_apps/storage/types/blob_storage.py b/harp_apps/storage/types/blob_storage.py index 56731edf..a3c76709 100644 --- a/harp_apps/storage/types/blob_storage.py +++ b/harp_apps/storage/types/blob_storage.py @@ -10,6 +10,8 @@ async def get(self, blob_id: str): ... async def put(self, blob: Blob) -> Blob: ... + async def force_put(self, blob: Blob) -> Blob: ... + async def delete(self, blob_id: str): ... async def exists(self, blob_id: str) -> bool: ...