-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
BREAKING(cache): allow caching long running results
```sql CREATE TABLE `cache` ( `key` VARCHAR(220) NOT NULL, `value` LONGTEXT NOT NULL, `expires` TIMESTAMP NOT NULL, PRIMARY KEY (`key`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; ``
- Loading branch information
Showing
7 changed files
with
103 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
from sqlalchemy import Column, String, Text, TIMESTAMP | ||
|
||
from . import Base | ||
|
||
|
||
class Cache(Base): | ||
__tablename__ = 'cache' | ||
__table_args__ = { | ||
'mysql_engine': 'InnoDB', | ||
'mysql_charset': 'utf8mb4' | ||
} | ||
|
||
key = Column(String(220), primary_key=True, nullable=False) | ||
value = Column(Text(), nullable=False) | ||
expires = Column(TIMESTAMP, nullable=False) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
from datetime import datetime, timedelta | ||
from typing import Optional | ||
from gzip import compress, decompress | ||
from pickle import dumps, loads | ||
from base64 import b64encode, b64decode | ||
|
||
from db import session | ||
from model.cache import Cache | ||
|
||
|
||
def get_key(user: Optional[int], role: Optional[str], year: Optional[int], subkey: str) -> str: | ||
""" | ||
Get a key for a user or role | ||
:param user: user ID | ||
:param role: role name | ||
:param subkey: key name | ||
:param year: year | ||
:return: key name | ||
""" | ||
year = int(year) if year is not None else None | ||
user = int(user) if user is not None else None | ||
return f"{user=}:{role=}:{year=}:{subkey=}" | ||
|
||
|
||
def get_record(key: str) -> Optional[any]: | ||
""" | ||
Get a record from cache | ||
:param key: key to get | ||
:return: data | ||
""" | ||
data = session.query(Cache).filter(Cache.key == key).first() | ||
if data is None: | ||
return None | ||
if datetime.now() > data.expires: | ||
invalidate_cache(key) | ||
return None | ||
return loads(decompress(b64decode(data.value.encode('ascii')))) | ||
|
||
|
||
def invalidate_cache(key: str) -> None: | ||
""" | ||
Invalidate cache | ||
:param key: key to invalidate | ||
""" | ||
session.query(Cache).filter(Cache.key == key).delete() | ||
session.commit() | ||
|
||
|
||
def save_cache(key: str, data: any, expires_second: int) -> None: | ||
""" | ||
Save data to cache | ||
:param expires_second: seconds until record is considered expired | ||
:param key: key to save | ||
:param data: data to save | ||
""" | ||
data = b64encode(compress(dumps(data))).decode('ascii') | ||
|
||
if get_record(key) is not None: | ||
session.query(Cache).filter(Cache.key == key).delete() | ||
expires = datetime.now() + timedelta(seconds=expires_second) | ||
session.add(Cache(key=key, value=data, expires=expires)) | ||
session.commit() |