mirror of
https://github.com/modrinth/code.git
synced 2026-08-25 09:04:55 +00:00
redo error handling in xredis
This commit is contained in:
@@ -12,8 +12,10 @@
|
||||
- no trailing punctuation
|
||||
- wrap code items e.g. type names in backticks
|
||||
- Prefer `wrap_internal_err`, `wrap_request_err` when attaching context to an existing error (like Anyhow `context` or Eyre `wrap_err`)
|
||||
- Prefer importing `eyre::Result` and using `Result<T>` instead of `eyre::Result<T>`
|
||||
- Prefer `eyre::Ok(value)` instead of `Ok::<_, eyre::Report>(value)` when an explicit Eyre result type is needed
|
||||
- All operations should ideally have some context attached
|
||||
- Database operations can have a message like `.wrap_internal_err("failed to fetch XYZ")`
|
||||
- Database operations can have a message like `.wrap_internal_err("fetching XYZ")`
|
||||
- You can perform real-time queries against the databases in the Docker Compose
|
||||
- `docker exec labrinth-postgres psql -c "select 1"`
|
||||
- `docker exec labrinth-redis redis-cli flushall`
|
||||
|
||||
@@ -59,12 +59,6 @@ pub enum AuthenticationError {
|
||||
Url,
|
||||
}
|
||||
|
||||
impl From<xredis::Error> for AuthenticationError {
|
||||
fn from(error: xredis::Error) -> Self {
|
||||
Self::Database(error.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl actix_web::ResponseError for AuthenticationError {
|
||||
fn status_code(&self) -> StatusCode {
|
||||
match self {
|
||||
|
||||
@@ -77,8 +77,6 @@ pub enum DatabaseError {
|
||||
SerdeCacheError(#[from] serde_json::Error),
|
||||
#[error("error while encoding or decoding the cache: {0}")]
|
||||
PostcardCacheError(#[from] postcard::Error),
|
||||
#[error(transparent)]
|
||||
Redis(#[from] xredis::Error),
|
||||
#[error("Schema error: {0}")]
|
||||
SchemaError(String),
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use crate::database::models::DatabaseError;
|
||||
use crate::models::v3::notifications::{NotificationChannel, NotificationType};
|
||||
use crate::routes::ApiError;
|
||||
use crate::util::error::Context;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use xredis::RedisPool;
|
||||
|
||||
@@ -123,12 +124,16 @@ where
|
||||
html: String,
|
||||
}
|
||||
|
||||
let mut redis_conn = redis.connect().await?;
|
||||
let mut redis_conn = redis.connect().await.wrap_internal_err(
|
||||
"connecting to redis for dynamic notification html",
|
||||
)?;
|
||||
let redis_key = redis_conn
|
||||
.key()
|
||||
.metadata(TEMPLATES_DYNAMIC_HTML_NAMESPACE, key);
|
||||
if let Some(body) =
|
||||
redis_conn.get_deserialized::<HtmlBody>(&redis_key).await?
|
||||
if let Some(body) = redis_conn
|
||||
.get_deserialized::<HtmlBody>(&redis_key)
|
||||
.await
|
||||
.wrap_internal_err("fetching dynamic notification html from redis")?
|
||||
{
|
||||
return Ok(body.html);
|
||||
}
|
||||
@@ -136,14 +141,17 @@ where
|
||||
drop(redis_conn);
|
||||
|
||||
let cached = HtmlBody { html: get().await? };
|
||||
let mut redis_conn = redis.connect().await?;
|
||||
let mut redis_conn = redis.connect().await.wrap_internal_err(
|
||||
"connecting to redis for dynamic notification html",
|
||||
)?;
|
||||
let redis_key = redis_conn
|
||||
.key()
|
||||
.metadata(TEMPLATES_DYNAMIC_HTML_NAMESPACE, key);
|
||||
|
||||
redis_conn
|
||||
.set_serialized(&redis_key, &cached, Some(HTML_DATA_CACHE_EXPIRY))
|
||||
.await?;
|
||||
.await
|
||||
.wrap_internal_err("writing dynamic notification html to redis")?;
|
||||
|
||||
Ok(cached.html)
|
||||
}
|
||||
|
||||
@@ -946,7 +946,7 @@ impl DBProject {
|
||||
},
|
||||
)
|
||||
.await
|
||||
.wrap_internal_err("failed to fetch cached projects")?;
|
||||
.wrap_internal_err("fetching cached projects")?;
|
||||
|
||||
Ok(val)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::env::ENV;
|
||||
use eyre::{Result, WrapErr};
|
||||
|
||||
struct RedisConfig {
|
||||
inner: xredis::RedisConfig,
|
||||
@@ -8,7 +9,7 @@ struct RedisConfig {
|
||||
}
|
||||
|
||||
impl RedisConfig {
|
||||
fn from_env() -> Result<Self, xredis::RedisConfigError> {
|
||||
fn from_env() -> Result<Self> {
|
||||
let inner = xredis::RedisConfig::new(
|
||||
ENV.REDIS_TOPOLOGY,
|
||||
ENV.REDIS_CONNECTION_TYPE,
|
||||
@@ -25,7 +26,8 @@ impl RedisConfig {
|
||||
(ENV.REDIS_BLOCKING_MAX_CONNECTIONS as usize, 0),
|
||||
ENV.REDIS_CACHE_LOCKING_STRATEGY,
|
||||
ENV.REDIS_READ_REPLICA_STRATEGY,
|
||||
)?;
|
||||
)
|
||||
.wrap_err("loading Redis configuration from environment")?;
|
||||
let cache_settings = xredis::CacheSettings {
|
||||
default_expiry: ENV.REDIS_DEFAULT_EXPIRY,
|
||||
actual_expiry: ENV.REDIS_ACTUAL_EXPIRY,
|
||||
|
||||
@@ -165,7 +165,7 @@ vars! {
|
||||
REDIS_BLOCKING_MAX_CONNECTIONS: u32 = 256u32;
|
||||
|
||||
// The encoding format used for Redis cache values.
|
||||
REDIS_ENCODING_FORMAT: xredis::EncodingFormat = xredis::EncodingFormat::Json;
|
||||
REDIS_ENCODING_FORMAT: xredis::EncodingFormat = xredis::EncodingFormat::Postcard;
|
||||
// The level of LZ4 compression used for Redis cache values. A value of 0 disables compression (supports 1-12)
|
||||
REDIS_COMPRESSION_LEVEL: i32 = 0i32;
|
||||
// The compression algorithm used for Redis cache values. Currently only LZ4 is supported.
|
||||
|
||||
@@ -4,6 +4,7 @@ use crate::models::analytics::{
|
||||
};
|
||||
use crate::routes::ApiError;
|
||||
use crate::routes::analytics::MINECRAFT_SERVER_PLAYS;
|
||||
use crate::util::error::Context;
|
||||
use dashmap::{DashMap, DashSet};
|
||||
use std::collections::HashMap;
|
||||
use tracing::trace;
|
||||
@@ -142,10 +143,15 @@ impl AnalyticsQueue {
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let mut redis_connection = redis.connect().await?;
|
||||
let mut redis_connection =
|
||||
redis.connect().await.wrap_internal_err(
|
||||
"connecting to redis for server play counts",
|
||||
)?;
|
||||
|
||||
let results =
|
||||
redis_connection.get_many_typed::<u32>(&redis_keys).await?;
|
||||
let results = redis_connection
|
||||
.get_many_typed::<u32>(&redis_keys)
|
||||
.await
|
||||
.wrap_internal_err("fetching server play counts from redis")?;
|
||||
for (idx, count) in results.into_iter().enumerate() {
|
||||
let new_count = if let Some(count) = count {
|
||||
if count >= MINECRAFT_SERVER_PLAYS_LIMIT {
|
||||
@@ -164,7 +170,8 @@ impl AnalyticsQueue {
|
||||
new_count,
|
||||
Some(MINECRAFT_SERVER_PLAYS_EXPIRY as i64),
|
||||
)
|
||||
.await?;
|
||||
.await
|
||||
.wrap_internal_err("writing server play count to redis")?;
|
||||
}
|
||||
|
||||
let mut plays = client
|
||||
@@ -198,10 +205,15 @@ impl AnalyticsQueue {
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let mut redis_connection = redis.connect().await?;
|
||||
let mut redis_connection = redis
|
||||
.connect()
|
||||
.await
|
||||
.wrap_internal_err("connecting to redis for view counts")?;
|
||||
|
||||
let results =
|
||||
redis_connection.get_many_typed::<u32>(&redis_keys).await?;
|
||||
let results = redis_connection
|
||||
.get_many_typed::<u32>(&redis_keys)
|
||||
.await
|
||||
.wrap_internal_err("fetching view counts from redis")?;
|
||||
for (idx, count) in results.into_iter().enumerate() {
|
||||
let new_count =
|
||||
if let Some((views, monetized)) = raw_views.get_mut(idx) {
|
||||
@@ -226,7 +238,8 @@ impl AnalyticsQueue {
|
||||
let key = &redis_keys[idx];
|
||||
redis_connection
|
||||
.set(key, new_count, Some(6 * 60 * 60))
|
||||
.await?;
|
||||
.await
|
||||
.wrap_internal_err("writing view count to redis")?;
|
||||
}
|
||||
|
||||
let mut views = client.insert::<PageView>("views").await?;
|
||||
@@ -267,10 +280,15 @@ impl AnalyticsQueue {
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let mut redis_connection = redis.connect().await?;
|
||||
let mut redis_connection = redis
|
||||
.connect()
|
||||
.await
|
||||
.wrap_internal_err("connecting to redis for download counts")?;
|
||||
|
||||
let results =
|
||||
redis_connection.get_many_typed::<u32>(&redis_keys).await?;
|
||||
let results = redis_connection
|
||||
.get_many_typed::<u32>(&redis_keys)
|
||||
.await
|
||||
.wrap_internal_err("fetching download counts from redis")?;
|
||||
for (idx, count) in results.into_iter().enumerate() {
|
||||
let new_count = if let Some(count) = count {
|
||||
if count > 5 {
|
||||
@@ -286,7 +304,8 @@ impl AnalyticsQueue {
|
||||
let key = &redis_keys[idx];
|
||||
redis_connection
|
||||
.set(key, new_count, Some(6 * 60 * 60))
|
||||
.await?;
|
||||
.await
|
||||
.wrap_internal_err("writing download count to redis")?;
|
||||
}
|
||||
|
||||
let mut transaction = pool.begin().await?;
|
||||
|
||||
@@ -267,12 +267,6 @@ pub enum ApiError {
|
||||
},
|
||||
}
|
||||
|
||||
impl From<xredis::Error> for ApiError {
|
||||
fn from(error: xredis::Error) -> Self {
|
||||
Self::Database(error.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl ApiError {
|
||||
pub fn delphi(err: impl Into<eyre::Error>) -> Self {
|
||||
Self::Delphi(err.into())
|
||||
|
||||
Reference in New Issue
Block a user