Move stream timeout to all response bodies

This commit is contained in:
Aode (lion) 2022-03-29 16:48:26 -05:00
parent 63d66050c8
commit 09281d9ae8
3 changed files with 21 additions and 23 deletions

View file

@ -119,6 +119,9 @@ pub(crate) enum UploadError {
#[error("Hit limit")] #[error("Hit limit")]
Limit(#[from] crate::stream::LimitError), Limit(#[from] crate::stream::LimitError),
#[error("Response timeout")]
Timeout(#[from] crate::stream::TimeoutError),
} }
impl From<awc::error::SendRequestError> for UploadError { impl From<awc::error::SendRequestError> for UploadError {

View file

@ -7,7 +7,7 @@ use actix_web::{
use awc::Client; use awc::Client;
use futures_util::{ use futures_util::{
stream::{empty, once}, stream::{empty, once},
Stream, TryStreamExt, Stream, StreamExt, TryStreamExt,
}; };
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use std::{ use std::{
@ -15,7 +15,7 @@ use std::{
future::ready, future::ready,
path::PathBuf, path::PathBuf,
sync::atomic::{AtomicU64, Ordering}, sync::atomic::{AtomicU64, Ordering},
time::SystemTime, time::{Duration, SystemTime},
}; };
use tokio::{io::AsyncReadExt, sync::Semaphore}; use tokio::{io::AsyncReadExt, sync::Semaphore};
use tracing::{debug, info, instrument}; use tracing::{debug, info, instrument};
@ -47,6 +47,8 @@ mod tmp_file;
mod upload_manager; mod upload_manager;
mod validate; mod validate;
use crate::stream::StreamTimeout;
use self::{ use self::{
concurrent_processor::CancelSafeProcessor, concurrent_processor::CancelSafeProcessor,
config::{Configuration, ImageFormat, Operation}, config::{Configuration, ImageFormat, Operation},
@ -486,6 +488,12 @@ where
E: std::error::Error + 'static, E: std::error::Error + 'static,
actix_web::Error: From<E>, actix_web::Error: From<E>,
{ {
let stream = stream.timeout(Duration::from_secs(5)).map(|res| match res {
Ok(Ok(item)) => Ok(item),
Ok(Err(e)) => Err(actix_web::Error::from(e)),
Err(e) => Err(Error::from(e).into()),
});
builder builder
.insert_header(LastModified(modified.into())) .insert_header(LastModified(modified.into()))
.insert_header(CacheControl(vec![ .insert_header(CacheControl(vec![

View file

@ -2,18 +2,13 @@ use crate::{
error::Error, error::Error,
repo::{Repo, SettingsRepo}, repo::{Repo, SettingsRepo},
store::Store, store::Store,
stream::StreamTimeout,
}; };
use actix_web::web::Bytes; use actix_web::web::Bytes;
use futures_util::{Stream, StreamExt}; use futures_util::{Stream, TryStreamExt};
use s3::{ use s3::{
client::Client, command::Command, creds::Credentials, request_trait::Request, Bucket, Region, client::Client, command::Command, creds::Credentials, request_trait::Request, Bucket, Region,
}; };
use std::{ use std::{pin::Pin, string::FromUtf8Error};
pin::Pin,
string::FromUtf8Error,
time::{Duration, Instant},
};
use storage_path_generator::{Generator, Path}; use storage_path_generator::{Generator, Path};
use tokio::io::{AsyncRead, AsyncWrite}; use tokio::io::{AsyncRead, AsyncWrite};
use tracing::Instrument; use tracing::Instrument;
@ -31,9 +26,6 @@ pub(crate) enum ObjectError {
#[error("Failed to generate path")] #[error("Failed to generate path")]
PathGenerator(#[from] storage_path_generator::PathError), PathGenerator(#[from] storage_path_generator::PathError),
#[error("Timeout")]
Elapsed,
#[error("Failed to parse string")] #[error("Failed to parse string")]
Utf8(#[from] FromUtf8Error), Utf8(#[from] FromUtf8Error),
@ -110,24 +102,19 @@ impl Store for ObjectStore {
) )
}); });
let now = Instant::now();
let allotted = Duration::from_secs(5);
let response = request_span let response = request_span
.in_scope(|| tokio::time::timeout(allotted, request.response())) .in_scope(|| request.response())
.instrument(request_span.clone()) .instrument(request_span.clone())
.await .await
.map_err(|_| ObjectError::Elapsed)?
.map_err(ObjectError::from)?; .map_err(ObjectError::from)?;
let allotted = allotted.saturating_sub(now.elapsed()); let stream = request_span.in_scope(|| {
response
let stream = response.bytes_stream().timeout(allotted).map(|res| { .bytes_stream()
res.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e)) .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))
.and_then(|res| res.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e)))
}); });
Ok(request_span.in_scope(|| Box::pin(stream))) Ok(Box::pin(stream))
} }
#[tracing::instrument(skip(writer))] #[tracing::instrument(skip(writer))]