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