refactor (backend-rs): use chrono::Duration for Redis cache TTL
This commit is contained in:
parent
47018b4cff
commit
e541efd80a
6 changed files with 47 additions and 19 deletions
37
packages/backend-rs/src/cache/redis.rs
vendored
37
packages/backend-rs/src/cache/redis.rs
vendored
|
@ -1,6 +1,7 @@
|
|||
//! Utilities for using Redis cache
|
||||
|
||||
use crate::database::{redis_conn, redis_key, RedisConnError};
|
||||
use chrono::Duration;
|
||||
use redis::{AsyncCommands, RedisError};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
|
@ -23,6 +24,8 @@ pub enum Error {
|
|||
RedisConn(#[from] RedisConnError),
|
||||
#[error("failed to encode data for Redis")]
|
||||
Encode(#[from] rmp_serde::encode::Error),
|
||||
#[error("invalid cache TTL")]
|
||||
TTL,
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -56,18 +59,19 @@ fn wildcard(category: Category) -> String {
|
|||
///
|
||||
/// * `key` : key (prefixed automatically)
|
||||
/// * `value` : (de)serializable value
|
||||
/// * `expire_seconds` : TTL
|
||||
/// * `ttl` : cache lifetime
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use backend_rs::cache;
|
||||
/// use chrono::Duration;
|
||||
/// # async fn f() -> Result<(), Box<dyn std::error::Error>> {
|
||||
/// let key = "apple";
|
||||
/// let data = "I want to cache this string".to_owned();
|
||||
///
|
||||
/// // caches the data for 10 seconds
|
||||
/// cache::set(key, &data, 10).await?;
|
||||
/// cache::set(key, &data, Duration::seconds(10)).await?;
|
||||
///
|
||||
/// // get the cache
|
||||
/// let cached_data = cache::get::<String>(key).await?;
|
||||
|
@ -80,14 +84,14 @@ fn wildcard(category: Category) -> String {
|
|||
pub async fn set<V: for<'a> Deserialize<'a> + Serialize>(
|
||||
key: &str,
|
||||
value: &V,
|
||||
expire_seconds: u64,
|
||||
ttl: Duration,
|
||||
) -> Result<(), Error> {
|
||||
redis_conn()
|
||||
.await?
|
||||
.set_ex(
|
||||
prefix_key(key),
|
||||
rmp_serde::encode::to_vec(&value)?,
|
||||
expire_seconds,
|
||||
ttl.num_seconds().try_into().map_err(|_| Error::TTL)?,
|
||||
)
|
||||
.await?;
|
||||
Ok(())
|
||||
|
@ -176,14 +180,14 @@ pub async fn delete(key: &str) -> Result<(), Error> {
|
|||
/// * `category` : one of [Category]
|
||||
/// * `key` : key (prefixed automatically)
|
||||
/// * `value` : (de)serializable value
|
||||
/// * `expire_seconds` : TTL
|
||||
/// * `ttl` : cache lifetime
|
||||
pub async fn set_one<V: for<'a> Deserialize<'a> + Serialize>(
|
||||
category: Category,
|
||||
key: &str,
|
||||
value: &V,
|
||||
expire_seconds: u64,
|
||||
ttl: Duration,
|
||||
) -> Result<(), Error> {
|
||||
set(&categorize(category, key), value, expire_seconds).await
|
||||
set(&categorize(category, key), value, ttl).await
|
||||
}
|
||||
|
||||
/// Gets a Redis cache under a `category`.
|
||||
|
@ -233,6 +237,7 @@ pub async fn delete_all(category: Category) -> Result<(), Error> {
|
|||
mod unit_test {
|
||||
use super::{delete_all, get, get_one, set, set_one, Category::Test};
|
||||
use crate::cache::delete_one;
|
||||
use chrono::Duration;
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
#[tokio::test]
|
||||
|
@ -256,9 +261,9 @@ mod unit_test {
|
|||
kind: "prime number".to_owned(),
|
||||
};
|
||||
|
||||
set(key_1, &value_1, 1).await.unwrap();
|
||||
set(key_2, &value_2, 1).await.unwrap();
|
||||
set(key_3, &value_3, 1).await.unwrap();
|
||||
set(key_1, &value_1, Duration::seconds(1)).await.unwrap();
|
||||
set(key_2, &value_2, Duration::seconds(1)).await.unwrap();
|
||||
set(key_3, &value_3, Duration::seconds(1)).await.unwrap();
|
||||
|
||||
let cached_value_1: Vec<i32> = get(key_1).await.unwrap().unwrap();
|
||||
let cached_value_2: String = get(key_2).await.unwrap().unwrap();
|
||||
|
@ -291,9 +296,15 @@ mod unit_test {
|
|||
let value_2 = 998244353u32;
|
||||
let value_3 = 'あ';
|
||||
|
||||
set_one(Test, key_1, &value_1, 5 * 60).await.unwrap();
|
||||
set_one(Test, key_2, &value_2, 5 * 60).await.unwrap();
|
||||
set_one(Test, key_3, &value_3, 5 * 60).await.unwrap();
|
||||
set_one(Test, key_1, &value_1, Duration::minutes(5))
|
||||
.await
|
||||
.unwrap();
|
||||
set_one(Test, key_2, &value_2, Duration::minutes(5))
|
||||
.await
|
||||
.unwrap();
|
||||
set_one(Test, key_3, &value_3, Duration::minutes(5))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
get_one::<String>(Test, key_1).await.unwrap().unwrap(),
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use crate::{cache, util::http_client};
|
||||
use chrono::Duration;
|
||||
use futures_util::AsyncReadExt;
|
||||
use image::{ImageError, ImageFormat, ImageReader};
|
||||
use isahc::AsyncReadResponseExt;
|
||||
|
@ -63,7 +64,7 @@ pub async fn get_image_size_from_url(url: &str) -> Result<ImageSize, Error> {
|
|||
.is_some();
|
||||
|
||||
if !attempted {
|
||||
cache::set_one(cache::Category::FetchUrl, url, &true, 10 * 60).await?;
|
||||
cache::set_one(cache::Category::FetchUrl, url, &true, Duration::minutes(10)).await?;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
//! Fetch latest Firefish version from the Firefish repository
|
||||
|
||||
use crate::{cache, util::http_client};
|
||||
use chrono::Duration;
|
||||
use futures_util::AsyncReadExt;
|
||||
use isahc::AsyncReadResponseExt;
|
||||
use serde::Deserialize;
|
||||
|
@ -65,7 +66,7 @@ pub async fn latest_version() -> Result<String, Error> {
|
|||
cache::Category::FetchUrl,
|
||||
UPSTREAM_PACKAGE_JSON_URL,
|
||||
&fetched_version,
|
||||
3 * 60 * 60,
|
||||
Duration::hours(3),
|
||||
)
|
||||
.await?;
|
||||
Ok(fetched_version)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use crate::cache;
|
||||
use chrono::Duration;
|
||||
use identicon_rs::{error::IdenticonError, Identicon};
|
||||
|
||||
#[macros::errors]
|
||||
|
@ -18,7 +19,13 @@ pub async fn generate(id: &str) -> Result<Vec<u8>, Error> {
|
|||
.set_border(16)
|
||||
.set_scale(96)?
|
||||
.export_png_data()?;
|
||||
cache::set_one(cache::Category::RandomIcon, id, &icon, 10 * 60).await?;
|
||||
cache::set_one(
|
||||
cache::Category::RandomIcon,
|
||||
id,
|
||||
&icon,
|
||||
Duration::minutes(10),
|
||||
)
|
||||
.await?;
|
||||
Ok(icon)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
//! Determine whether to enable the cat language conversion
|
||||
|
||||
use crate::{cache, database::db_conn, model::entity::user};
|
||||
use chrono::Duration;
|
||||
use sea_orm::{DbErr, EntityTrait, QuerySelect, SelectColumns};
|
||||
|
||||
#[macros::errors]
|
||||
|
@ -35,7 +36,7 @@ pub async fn should_nyaify(reader_user_id: &str) -> Result<bool, Error> {
|
|||
cache::Category::CatLang,
|
||||
reader_user_id,
|
||||
&fetched_value,
|
||||
10 * 60,
|
||||
Duration::minutes(10),
|
||||
)
|
||||
.await?;
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ use crate::{
|
|||
federation::acct::Acct,
|
||||
model::entity::{antenna, blocking, following, note, sea_orm_active_enums::*},
|
||||
};
|
||||
use chrono::Duration;
|
||||
use sea_orm::{prelude::*, QuerySelect};
|
||||
|
||||
#[macros::errors]
|
||||
|
@ -109,7 +110,13 @@ pub(super) async fn check_hit_antenna(
|
|||
.into_tuple::<String>()
|
||||
.all(db)
|
||||
.await?;
|
||||
cache::set_one(cache::Category::Block, ¬e.user_id, &blocks, 10 * 60).await?;
|
||||
cache::set_one(
|
||||
cache::Category::Block,
|
||||
¬e.user_id,
|
||||
&blocks,
|
||||
Duration::minutes(10),
|
||||
)
|
||||
.await?;
|
||||
blocks
|
||||
};
|
||||
|
||||
|
@ -138,7 +145,7 @@ pub(super) async fn check_hit_antenna(
|
|||
cache::Category::Follow,
|
||||
&antenna.user_id,
|
||||
&following,
|
||||
10 * 60,
|
||||
Duration::minutes(10),
|
||||
)
|
||||
.await?;
|
||||
following
|
||||
|
|
Loading…
Reference in a new issue