Refactor database error handling across repositories to use IntoDbResult for improved error management
Some checks failed
lint / lint (push) Has been cancelled
test / unit (push) Has been cancelled
test / integration (push) Has been cancelled
lint / lint (pull_request) Failing after 9m30s
test / unit (pull_request) Successful in 16m10s
test / integration (pull_request) Failing after 16m44s

- Updated PgNotificationRepository to utilize IntoDbResult for error handling in various methods.
- Refactored PgRemoteActorRepository to replace manual error mapping with IntoDbResult.
- Modified PgRemoteActorConnectionRepository to implement IntoDbResult for error handling.
- Adjusted PgTagRepository to use IntoDbResult for consistent error management.
- Introduced test_helpers module for seeding users and thoughts in tests.
- Enhanced PgThoughtRepository to leverage IntoDbResult for error handling.
- Updated PgTopFriendRepository to utilize IntoDbResult for error management.
- Refactored PgUserRepository to implement IntoDbResult for error handling.
- Added constants for pagination defaults in requests.
- Introduced MAX_TOP_FRIENDS constant for top friends validation.
- Refactored JWT expiration time to use a constant.
- Improved rate limiter configuration with constants for better readability.
- Added utility methods for FollowState and Visibility enums for string conversions.
- Introduced maximum length constants for Username, Email, and Content value objects.
- Cleaned up test modules by removing redundant code and utilizing a shared testing state.
This commit is contained in:
2026-05-15 12:31:25 +02:00
parent a040a38036
commit 314dad5451
40 changed files with 456 additions and 690 deletions

View File

@@ -27,6 +27,11 @@ use crate::{
webfinger::webfinger_handler,
};
const DELIVERY_MAX_ATTEMPTS: u32 = 3;
const DELIVERY_INITIAL_DELAY_SECS: u64 = 1;
const HTTP_FETCH_TIMEOUT_SECS: u64 = 30;
const BATCH_FETCH_SLEEP_MS: u64 = 100;
fn content_to_html(text: &str) -> String {
let escaped = text
.replace('&', "&")
@@ -139,11 +144,11 @@ pub(crate) async fn send_with_retry(
) -> Vec<anyhow::Error> {
let mut failures = vec![];
for send in sends {
let mut delay = std::time::Duration::from_secs(1);
for attempt in 1..=3u32 {
let mut delay = std::time::Duration::from_secs(DELIVERY_INITIAL_DELAY_SECS);
for attempt in 1..=DELIVERY_MAX_ATTEMPTS {
match send.clone().sign_and_send(data).await {
Ok(()) => break,
Err(e) if attempt < 3 => {
Err(e) if attempt < DELIVERY_MAX_ATTEMPTS => {
tracing::warn!(attempt, error = %e, "delivery failed, retrying");
tokio::time::sleep(delay).await;
delay *= 2;
@@ -1206,7 +1211,7 @@ impl ActivityPubService {
pub async fn backfill_outbox(&self, outbox_url: &str, actor_url: &str) -> anyhow::Result<()> {
let client = reqwest::Client::builder()
.timeout(std::time::Duration::from_secs(30))
.timeout(std::time::Duration::from_secs(HTTP_FETCH_TIMEOUT_SECS))
.build()?;
let data = self.federation_config.to_request_data();
let actor = url::Url::parse(actor_url)?;
@@ -1384,7 +1389,7 @@ impl ActivityPubService {
failure_count += 1;
}
}
tokio::time::sleep(std::time::Duration::from_millis(100)).await;
tokio::time::sleep(std::time::Duration::from_millis(BATCH_FETCH_SLEEP_MS)).await;
}
tracing::info!(
@@ -1705,16 +1710,16 @@ impl domain::ports::FederationActionPort for ActivityPubService {
.map_err(|e| domain::errors::DomainError::ExternalService(e.to_string()))?;
let obj = if let Some(p) = page {
let p = p.max(1);
let offset = (p.saturating_sub(1) as usize) * 20;
let offset = (p.saturating_sub(1) as usize) * crate::urls::AP_PAGE_SIZE;
let followers = data
.federation_repo
.get_followers_page(uuid, offset as u32, 20)
.get_followers_page(uuid, offset as u32, crate::urls::AP_PAGE_SIZE)
.await
.map_err(|e| domain::errors::DomainError::ExternalService(e.to_string()))?;
let has_next = offset + followers.len() < total;
let items: Vec<String> = followers.into_iter().map(|f| f.actor.url).collect();
let mut obj = serde_json::json!({
"@context": "https://www.w3.org/ns/activitystreams",
"@context": crate::urls::AP_CONTEXT,
"type": "OrderedCollectionPage",
"id": format!("{}?page={}", collection_id, p),
"partOf": collection_id,
@@ -1727,7 +1732,7 @@ impl domain::ports::FederationActionPort for ActivityPubService {
obj
} else {
serde_json::json!({
"@context": "https://www.w3.org/ns/activitystreams",
"@context": crate::urls::AP_CONTEXT,
"type": "OrderedCollection",
"id": collection_id,
"totalItems": total,
@@ -1753,16 +1758,16 @@ impl domain::ports::FederationActionPort for ActivityPubService {
.map_err(|e| domain::errors::DomainError::ExternalService(e.to_string()))?;
let obj = if let Some(p) = page {
let p = p.max(1);
let offset = (p.saturating_sub(1) as usize) * 20;
let offset = (p.saturating_sub(1) as usize) * crate::urls::AP_PAGE_SIZE;
let following = data
.federation_repo
.get_following_page(uuid, offset as u32, 20)
.get_following_page(uuid, offset as u32, crate::urls::AP_PAGE_SIZE)
.await
.map_err(|e| domain::errors::DomainError::ExternalService(e.to_string()))?;
let has_next = offset + following.len() < total;
let items: Vec<String> = following.into_iter().map(|a| a.url).collect();
let mut obj = serde_json::json!({
"@context": "https://www.w3.org/ns/activitystreams",
"@context": crate::urls::AP_CONTEXT,
"type": "OrderedCollectionPage",
"id": format!("{}?page={}", collection_id, p),
"partOf": collection_id,
@@ -1775,7 +1780,7 @@ impl domain::ports::FederationActionPort for ActivityPubService {
obj
} else {
serde_json::json!({
"@context": "https://www.w3.org/ns/activitystreams",
"@context": crate::urls::AP_CONTEXT,
"type": "OrderedCollection",
"id": collection_id,
"totalItems": total,