mirror of
https://git.asonix.dog/asonix/pict-rs
synced 2024-12-22 19:31:35 +00:00
postgres: add already-claimed case, general: tracing paranoia
This commit is contained in:
parent
31caea438e
commit
a43de122f9
15 changed files with 234 additions and 189 deletions
|
@ -82,14 +82,12 @@ impl Drop for Backgrounded {
|
||||||
|
|
||||||
let cleanup_span = tracing::info_span!(parent: &cleanup_parent_span, "Backgrounded cleanup Identifier", identifier = ?identifier);
|
let cleanup_span = tracing::info_span!(parent: &cleanup_parent_span, "Backgrounded cleanup Identifier", identifier = ?identifier);
|
||||||
|
|
||||||
tracing::trace_span!(parent: None, "Spawn task").in_scope(|| {
|
crate::sync::spawn(
|
||||||
actix_rt::spawn(
|
|
||||||
async move {
|
async move {
|
||||||
let _ = crate::queue::cleanup_identifier(&repo, &identifier).await;
|
let _ = crate::queue::cleanup_identifier(&repo, &identifier).await;
|
||||||
}
|
}
|
||||||
.instrument(cleanup_span),
|
.instrument(cleanup_span),
|
||||||
)
|
);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(upload_id) = self.upload_id {
|
if let Some(upload_id) = self.upload_id {
|
||||||
|
@ -97,14 +95,12 @@ impl Drop for Backgrounded {
|
||||||
|
|
||||||
let cleanup_span = tracing::info_span!(parent: &cleanup_parent_span, "Backgrounded cleanup Upload ID", upload_id = ?upload_id);
|
let cleanup_span = tracing::info_span!(parent: &cleanup_parent_span, "Backgrounded cleanup Upload ID", upload_id = ?upload_id);
|
||||||
|
|
||||||
tracing::trace_span!(parent: None, "Spawn task").in_scope(|| {
|
crate::sync::spawn(
|
||||||
actix_rt::spawn(
|
|
||||||
async move {
|
async move {
|
||||||
let _ = repo.claim(upload_id).await;
|
let _ = repo.claim(upload_id).await;
|
||||||
}
|
}
|
||||||
.instrument(cleanup_span),
|
.instrument(cleanup_span),
|
||||||
)
|
);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -446,15 +446,15 @@ mod io_uring {
|
||||||
actix_rt::System::new().block_on(async move {
|
actix_rt::System::new().block_on(async move {
|
||||||
let arbiter = actix_rt::Arbiter::new();
|
let arbiter = actix_rt::Arbiter::new();
|
||||||
|
|
||||||
let (tx, rx) = tokio::sync::oneshot::channel();
|
let (tx, rx) = crate::sync::channel(1);
|
||||||
|
|
||||||
arbiter.spawn(async move {
|
arbiter.spawn(async move {
|
||||||
let handle = actix_rt::spawn($fut);
|
let handle = crate::sync::spawn($fut);
|
||||||
|
|
||||||
let _ = tx.send(handle.await.unwrap());
|
let _ = tx.send(handle.await.unwrap());
|
||||||
});
|
});
|
||||||
|
|
||||||
rx.await.unwrap()
|
rx.into_recv_async().await.unwrap()
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -217,14 +217,12 @@ impl Drop for Session {
|
||||||
|
|
||||||
let cleanup_span = tracing::info_span!(parent: &cleanup_parent_span, "Session cleanup hash", hash = ?hash);
|
let cleanup_span = tracing::info_span!(parent: &cleanup_parent_span, "Session cleanup hash", hash = ?hash);
|
||||||
|
|
||||||
tracing::trace_span!(parent: None, "Spawn task").in_scope(|| {
|
crate::sync::spawn(
|
||||||
actix_rt::spawn(
|
|
||||||
async move {
|
async move {
|
||||||
let _ = crate::queue::cleanup_hash(&repo, hash).await;
|
let _ = crate::queue::cleanup_hash(&repo, hash).await;
|
||||||
}
|
}
|
||||||
.instrument(cleanup_span),
|
.instrument(cleanup_span),
|
||||||
)
|
);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(alias) = self.alias.take() {
|
if let Some(alias) = self.alias.take() {
|
||||||
|
@ -233,14 +231,12 @@ impl Drop for Session {
|
||||||
|
|
||||||
let cleanup_span = tracing::info_span!(parent: &cleanup_parent_span, "Session cleanup alias", alias = ?alias);
|
let cleanup_span = tracing::info_span!(parent: &cleanup_parent_span, "Session cleanup alias", alias = ?alias);
|
||||||
|
|
||||||
tracing::trace_span!(parent: None, "Spawn task").in_scope(|| {
|
crate::sync::spawn(
|
||||||
actix_rt::spawn(
|
|
||||||
async move {
|
async move {
|
||||||
let _ = crate::queue::cleanup_alias(&repo, alias, token).await;
|
let _ = crate::queue::cleanup_alias(&repo, alias, token).await;
|
||||||
}
|
}
|
||||||
.instrument(cleanup_span),
|
.instrument(cleanup_span),
|
||||||
)
|
);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(identifier) = self.identifier.take() {
|
if let Some(identifier) = self.identifier.take() {
|
||||||
|
@ -248,14 +244,12 @@ impl Drop for Session {
|
||||||
|
|
||||||
let cleanup_span = tracing::info_span!(parent: &cleanup_parent_span, "Session cleanup identifier", identifier = ?identifier);
|
let cleanup_span = tracing::info_span!(parent: &cleanup_parent_span, "Session cleanup identifier", identifier = ?identifier);
|
||||||
|
|
||||||
tracing::trace_span!(parent: None, "Spawn task").in_scope(|| {
|
crate::sync::spawn(
|
||||||
actix_rt::spawn(
|
|
||||||
async move {
|
async move {
|
||||||
let _ = crate::queue::cleanup_identifier(&repo, &identifier).await;
|
let _ = crate::queue::cleanup_identifier(&repo, &identifier).await;
|
||||||
}
|
}
|
||||||
.instrument(cleanup_span),
|
.instrument(cleanup_span),
|
||||||
)
|
);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,16 +82,15 @@ mod test {
|
||||||
actix_rt::System::new().block_on(async move {
|
actix_rt::System::new().block_on(async move {
|
||||||
let arbiter = actix_rt::Arbiter::new();
|
let arbiter = actix_rt::Arbiter::new();
|
||||||
|
|
||||||
let (tx, rx) = tracing::trace_span!(parent: None, "Create channel")
|
let (tx, rx) = crate::sync::channel(1);
|
||||||
.in_scope(|| tokio::sync::oneshot::channel());
|
|
||||||
|
|
||||||
arbiter.spawn(async move {
|
arbiter.spawn(async move {
|
||||||
let handle = actix_rt::spawn($fut);
|
let handle = crate::sync::spawn($fut);
|
||||||
|
|
||||||
let _ = tx.send(handle.await.unwrap());
|
let _ = tx.send(handle.await.unwrap());
|
||||||
});
|
});
|
||||||
|
|
||||||
rx.await.unwrap()
|
rx.into_recv_async().await.unwrap()
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
19
src/lib.rs
19
src/lib.rs
|
@ -26,6 +26,7 @@ mod repo_04;
|
||||||
mod serde_str;
|
mod serde_str;
|
||||||
mod store;
|
mod store;
|
||||||
mod stream;
|
mod stream;
|
||||||
|
mod sync;
|
||||||
mod tmp_file;
|
mod tmp_file;
|
||||||
mod validate;
|
mod validate;
|
||||||
|
|
||||||
|
@ -84,8 +85,9 @@ const DAYS: u32 = 24 * HOURS;
|
||||||
const NOT_FOUND_KEY: &str = "404-alias";
|
const NOT_FOUND_KEY: &str = "404-alias";
|
||||||
|
|
||||||
static PROCESS_SEMAPHORE: Lazy<Semaphore> = Lazy::new(|| {
|
static PROCESS_SEMAPHORE: Lazy<Semaphore> = Lazy::new(|| {
|
||||||
tracing::trace_span!(parent: None, "Initialize semaphore")
|
let permits = num_cpus::get().saturating_sub(1).max(1);
|
||||||
.in_scope(|| Semaphore::new(num_cpus::get().saturating_sub(1).max(1)))
|
|
||||||
|
crate::sync::bare_semaphore(permits)
|
||||||
});
|
});
|
||||||
|
|
||||||
async fn ensure_details<S: Store + 'static>(
|
async fn ensure_details<S: Store + 'static>(
|
||||||
|
@ -1671,8 +1673,7 @@ fn spawn_cleanup(repo: ArcRepo, config: &Configuration) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
tracing::trace_span!(parent: None, "Spawn task").in_scope(|| {
|
crate::sync::spawn(async move {
|
||||||
actix_rt::spawn(async move {
|
|
||||||
let mut interval = actix_rt::time::interval(Duration::from_secs(30));
|
let mut interval = actix_rt::time::interval(Duration::from_secs(30));
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
@ -1693,22 +1694,18 @@ fn spawn_cleanup(repo: ArcRepo, config: &Configuration) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn spawn_workers<S>(repo: ArcRepo, store: S, config: Configuration, process_map: ProcessMap)
|
fn spawn_workers<S>(repo: ArcRepo, store: S, config: Configuration, process_map: ProcessMap)
|
||||||
where
|
where
|
||||||
S: Store + 'static,
|
S: Store + 'static,
|
||||||
{
|
{
|
||||||
tracing::trace_span!(parent: None, "Spawn task").in_scope(|| {
|
crate::sync::spawn(queue::process_cleanup(
|
||||||
actix_rt::spawn(queue::process_cleanup(
|
|
||||||
repo.clone(),
|
repo.clone(),
|
||||||
store.clone(),
|
store.clone(),
|
||||||
config.clone(),
|
config.clone(),
|
||||||
))
|
));
|
||||||
});
|
crate::sync::spawn(queue::process_images(repo, store, process_map, config));
|
||||||
tracing::trace_span!(parent: None, "Spawn task")
|
|
||||||
.in_scope(|| actix_rt::spawn(queue::process_images(repo, store, process_map, config)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn launch_file_store<F: Fn(&mut web::ServiceConfig) + Send + Clone + 'static>(
|
async fn launch_file_store<F: Fn(&mut web::ServiceConfig) + Send + Clone + 'static>(
|
||||||
|
|
|
@ -61,7 +61,7 @@ where
|
||||||
tracing::warn!("Retrying migration +{failure_count}");
|
tracing::warn!("Retrying migration +{failure_count}");
|
||||||
}
|
}
|
||||||
|
|
||||||
tokio::time::sleep(Duration::from_secs(3)).await;
|
actix_rt::time::sleep(Duration::from_secs(3)).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -364,7 +364,7 @@ where
|
||||||
tracing::warn!("Failed moving file. Retrying +{failure_count}");
|
tracing::warn!("Failed moving file. Retrying +{failure_count}");
|
||||||
}
|
}
|
||||||
|
|
||||||
tokio::time::sleep(Duration::from_secs(3)).await;
|
actix_rt::time::sleep(Duration::from_secs(3)).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use actix_rt::task::JoinHandle;
|
use actix_rt::task::JoinHandle;
|
||||||
use actix_web::web::Bytes;
|
use actix_web::web::Bytes;
|
||||||
|
use flume::r#async::RecvFut;
|
||||||
use std::{
|
use std::{
|
||||||
future::Future,
|
future::Future,
|
||||||
pin::Pin,
|
pin::Pin,
|
||||||
|
@ -10,7 +11,6 @@ use std::{
|
||||||
use tokio::{
|
use tokio::{
|
||||||
io::{AsyncRead, AsyncWriteExt, ReadBuf},
|
io::{AsyncRead, AsyncWriteExt, ReadBuf},
|
||||||
process::{Child, ChildStdin, ChildStdout, Command},
|
process::{Child, ChildStdin, ChildStdout, Command},
|
||||||
sync::oneshot::{channel, Receiver},
|
|
||||||
};
|
};
|
||||||
use tracing::{Instrument, Span};
|
use tracing::{Instrument, Span};
|
||||||
|
|
||||||
|
@ -73,7 +73,7 @@ struct DropHandle {
|
||||||
|
|
||||||
pub(crate) struct ProcessRead<I> {
|
pub(crate) struct ProcessRead<I> {
|
||||||
inner: I,
|
inner: I,
|
||||||
err_recv: Receiver<std::io::Error>,
|
err_recv: RecvFut<'static, std::io::Error>,
|
||||||
err_closed: bool,
|
err_closed: bool,
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
handle: DropHandle,
|
handle: DropHandle,
|
||||||
|
@ -206,14 +206,13 @@ impl Process {
|
||||||
let stdin = child.stdin.take().expect("stdin exists");
|
let stdin = child.stdin.take().expect("stdin exists");
|
||||||
let stdout = child.stdout.take().expect("stdout exists");
|
let stdout = child.stdout.take().expect("stdout exists");
|
||||||
|
|
||||||
let (tx, rx) = tracing::trace_span!(parent: None, "Create channel", %command)
|
let (tx, rx) = crate::sync::channel::<std::io::Error>(1);
|
||||||
.in_scope(channel::<std::io::Error>);
|
let rx = rx.into_recv_async();
|
||||||
|
|
||||||
let span = tracing::info_span!(parent: None, "Background process task", %command);
|
let span = tracing::info_span!(parent: None, "Background process task", %command);
|
||||||
span.follows_from(Span::current());
|
span.follows_from(Span::current());
|
||||||
|
|
||||||
let handle = tracing::trace_span!(parent: None, "Spawn task", %command).in_scope(|| {
|
let handle = crate::sync::spawn(
|
||||||
actix_rt::spawn(
|
|
||||||
async move {
|
async move {
|
||||||
let child_fut = async {
|
let child_fut = async {
|
||||||
(f)(stdin).await?;
|
(f)(stdin).await?;
|
||||||
|
@ -237,8 +236,7 @@ impl Process {
|
||||||
let _ = child.kill().await;
|
let _ = child.kill().await;
|
||||||
}
|
}
|
||||||
.instrument(span),
|
.instrument(span),
|
||||||
)
|
);
|
||||||
});
|
|
||||||
|
|
||||||
let sleep = actix_rt::time::sleep(timeout);
|
let sleep = actix_rt::time::sleep(timeout);
|
||||||
|
|
||||||
|
|
|
@ -86,7 +86,7 @@ where
|
||||||
let repo = repo.clone();
|
let repo = repo.clone();
|
||||||
|
|
||||||
let media = media.clone();
|
let media = media.clone();
|
||||||
let error_boundary = actix_rt::spawn(async move {
|
let error_boundary = crate::sync::spawn(async move {
|
||||||
let stream = store2
|
let stream = store2
|
||||||
.to_stream(&ident, None, None)
|
.to_stream(&ident, None, None)
|
||||||
.await?
|
.await?
|
||||||
|
|
|
@ -20,7 +20,8 @@ use diesel_async::{
|
||||||
AsyncConnection, AsyncPgConnection, RunQueryDsl,
|
AsyncConnection, AsyncPgConnection, RunQueryDsl,
|
||||||
};
|
};
|
||||||
use tokio::sync::Notify;
|
use tokio::sync::Notify;
|
||||||
use tokio_postgres::{AsyncMessage, Notification};
|
use tokio_postgres::{tls::NoTlsStream, AsyncMessage, Connection, NoTls, Notification, Socket};
|
||||||
|
use tracing::Instrument;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
@ -64,7 +65,7 @@ async fn delegate_notifications(receiver: flume::Receiver<Notification>, inner:
|
||||||
inner
|
inner
|
||||||
.queue_notifications
|
.queue_notifications
|
||||||
.entry(queue_name)
|
.entry(queue_name)
|
||||||
.or_insert_with(|| Arc::new(Notify::new()))
|
.or_insert_with(crate::sync::notify)
|
||||||
.notify_waiters();
|
.notify_waiters();
|
||||||
}
|
}
|
||||||
"upload_completion_channel" => {
|
"upload_completion_channel" => {
|
||||||
|
@ -134,12 +135,11 @@ impl PostgresError {
|
||||||
|
|
||||||
impl PostgresRepo {
|
impl PostgresRepo {
|
||||||
pub(crate) async fn connect(postgres_url: Url) -> Result<Self, ConnectPostgresError> {
|
pub(crate) async fn connect(postgres_url: Url) -> Result<Self, ConnectPostgresError> {
|
||||||
let (mut client, conn) =
|
let (mut client, conn) = tokio_postgres::connect(postgres_url.as_str(), NoTls)
|
||||||
tokio_postgres::connect(postgres_url.as_str(), tokio_postgres::tls::NoTls)
|
|
||||||
.await
|
.await
|
||||||
.map_err(ConnectPostgresError::ConnectForMigration)?;
|
.map_err(ConnectPostgresError::ConnectForMigration)?;
|
||||||
|
|
||||||
let handle = actix_rt::spawn(conn);
|
let handle = crate::sync::spawn(conn);
|
||||||
|
|
||||||
embedded::migrations::runner()
|
embedded::migrations::runner()
|
||||||
.run_async(&mut client)
|
.run_async(&mut client)
|
||||||
|
@ -166,10 +166,12 @@ impl PostgresRepo {
|
||||||
health_count: AtomicU64::new(0),
|
health_count: AtomicU64::new(0),
|
||||||
pool,
|
pool,
|
||||||
queue_notifications: DashMap::new(),
|
queue_notifications: DashMap::new(),
|
||||||
upload_notifier: Notify::new(),
|
upload_notifier: crate::sync::bare_notify(),
|
||||||
});
|
});
|
||||||
|
|
||||||
let notifications = Arc::new(actix_rt::spawn(delegate_notifications(rx, inner.clone())));
|
let handle = crate::sync::spawn(delegate_notifications(rx, inner.clone()));
|
||||||
|
|
||||||
|
let notifications = Arc::new(handle);
|
||||||
|
|
||||||
Ok(PostgresRepo {
|
Ok(PostgresRepo {
|
||||||
inner,
|
inner,
|
||||||
|
@ -198,14 +200,31 @@ fn build_handler(sender: flume::Sender<Notification>) -> ConfigFn {
|
||||||
move |config: &str| -> BoxFuture<'_, ConnectionResult<AsyncPgConnection>> {
|
move |config: &str| -> BoxFuture<'_, ConnectionResult<AsyncPgConnection>> {
|
||||||
let sender = sender.clone();
|
let sender = sender.clone();
|
||||||
|
|
||||||
Box::pin(async move {
|
let connect_span = tracing::trace_span!(parent: None, "connect future");
|
||||||
let (client, mut conn) =
|
|
||||||
|
Box::pin(
|
||||||
|
async move {
|
||||||
|
let (client, conn) =
|
||||||
tokio_postgres::connect(config, tokio_postgres::tls::NoTls)
|
tokio_postgres::connect(config, tokio_postgres::tls::NoTls)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| ConnectionError::BadConnection(e.to_string()))?;
|
.map_err(|e| ConnectionError::BadConnection(e.to_string()))?;
|
||||||
|
|
||||||
// not very cash money (structured concurrency) of me
|
// not very cash money (structured concurrency) of me
|
||||||
actix_rt::spawn(async move {
|
spawn_db_notification_task(sender, conn);
|
||||||
|
|
||||||
|
AsyncPgConnection::try_from(client).await
|
||||||
|
}
|
||||||
|
.instrument(connect_span),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn spawn_db_notification_task(
|
||||||
|
sender: flume::Sender<Notification>,
|
||||||
|
mut conn: Connection<Socket, NoTlsStream>,
|
||||||
|
) {
|
||||||
|
crate::sync::spawn(async move {
|
||||||
while let Some(res) = std::future::poll_fn(|cx| conn.poll_message(cx)).await {
|
while let Some(res) = std::future::poll_fn(|cx| conn.poll_message(cx)).await {
|
||||||
match res {
|
match res {
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
@ -226,11 +245,6 @@ fn build_handler(sender: flume::Sender<Notification>) -> ConfigFn {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
AsyncPgConnection::try_from(client).await
|
|
||||||
})
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_primitive(timestamp: time::OffsetDateTime) -> time::PrimitiveDateTime {
|
fn to_primitive(timestamp: time::OffsetDateTime) -> time::PrimitiveDateTime {
|
||||||
|
@ -849,7 +863,7 @@ impl QueueRepo for PostgresRepo {
|
||||||
.inner
|
.inner
|
||||||
.queue_notifications
|
.queue_notifications
|
||||||
.entry(String::from(queue_name))
|
.entry(String::from(queue_name))
|
||||||
.or_insert_with(|| Arc::new(Notify::new()))
|
.or_insert_with(crate::sync::notify)
|
||||||
.clone();
|
.clone();
|
||||||
|
|
||||||
diesel::sql_query("LISTEN queue_status_channel;")
|
diesel::sql_query("LISTEN queue_status_channel;")
|
||||||
|
@ -1330,21 +1344,28 @@ impl UploadRepo for PostgresRepo {
|
||||||
.await
|
.await
|
||||||
.map_err(PostgresError::Diesel)?;
|
.map_err(PostgresError::Diesel)?;
|
||||||
|
|
||||||
let opt = uploads
|
let nested_opt = uploads
|
||||||
.select(result)
|
.select(result)
|
||||||
.filter(id.eq(upload_id.id))
|
.filter(id.eq(upload_id.id))
|
||||||
.get_result(&mut conn)
|
.get_result(&mut conn)
|
||||||
.await
|
.await
|
||||||
.optional()
|
.optional()
|
||||||
.map_err(PostgresError::Diesel)?
|
.map_err(PostgresError::Diesel)?;
|
||||||
.flatten();
|
|
||||||
|
|
||||||
|
match nested_opt {
|
||||||
|
Some(opt) => {
|
||||||
if let Some(upload_result) = opt {
|
if let Some(upload_result) = opt {
|
||||||
let upload_result: InnerUploadResult = serde_json::from_value(upload_result)
|
let upload_result: InnerUploadResult =
|
||||||
|
serde_json::from_value(upload_result)
|
||||||
.map_err(PostgresError::DeserializeUploadResult)?;
|
.map_err(PostgresError::DeserializeUploadResult)?;
|
||||||
|
|
||||||
return Ok(upload_result.into());
|
return Ok(upload_result.into());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
return Err(RepoError::AlreadyClaimed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
drop(conn);
|
drop(conn);
|
||||||
|
|
||||||
|
|
|
@ -29,9 +29,7 @@ macro_rules! b {
|
||||||
($self:ident.$ident:ident, $expr:expr) => {{
|
($self:ident.$ident:ident, $expr:expr) => {{
|
||||||
let $ident = $self.$ident.clone();
|
let $ident = $self.$ident.clone();
|
||||||
|
|
||||||
let span = tracing::Span::current();
|
crate::sync::spawn_blocking(move || $expr)
|
||||||
|
|
||||||
actix_rt::task::spawn_blocking(move || span.in_scope(|| $expr))
|
|
||||||
.await
|
.await
|
||||||
.map_err(SledError::from)
|
.map_err(SledError::from)
|
||||||
.map_err(RepoError::from)?
|
.map_err(RepoError::from)?
|
||||||
|
@ -175,7 +173,7 @@ impl SledRepo {
|
||||||
|
|
||||||
let this = self.db.clone();
|
let this = self.db.clone();
|
||||||
|
|
||||||
actix_rt::task::spawn_blocking(move || {
|
crate::sync::spawn_blocking(move || {
|
||||||
let export = this.export();
|
let export = this.export();
|
||||||
export_db.import(export);
|
export_db.import(export);
|
||||||
})
|
})
|
||||||
|
@ -258,7 +256,7 @@ impl AliasAccessRepo for SledRepo {
|
||||||
let alias_access = self.alias_access.clone();
|
let alias_access = self.alias_access.clone();
|
||||||
let inverse_alias_access = self.inverse_alias_access.clone();
|
let inverse_alias_access = self.inverse_alias_access.clone();
|
||||||
|
|
||||||
let res = actix_rt::task::spawn_blocking(move || {
|
let res = crate::sync::spawn_blocking(move || {
|
||||||
(&alias_access, &inverse_alias_access).transaction(
|
(&alias_access, &inverse_alias_access).transaction(
|
||||||
|(alias_access, inverse_alias_access)| {
|
|(alias_access, inverse_alias_access)| {
|
||||||
if let Some(old) = alias_access.insert(alias.to_bytes(), &value_bytes)? {
|
if let Some(old) = alias_access.insert(alias.to_bytes(), &value_bytes)? {
|
||||||
|
@ -324,7 +322,7 @@ impl AliasAccessRepo for SledRepo {
|
||||||
let alias_access = self.alias_access.clone();
|
let alias_access = self.alias_access.clone();
|
||||||
let inverse_alias_access = self.inverse_alias_access.clone();
|
let inverse_alias_access = self.inverse_alias_access.clone();
|
||||||
|
|
||||||
let res = actix_rt::task::spawn_blocking(move || {
|
let res = crate::sync::spawn_blocking(move || {
|
||||||
(&alias_access, &inverse_alias_access).transaction(
|
(&alias_access, &inverse_alias_access).transaction(
|
||||||
|(alias_access, inverse_alias_access)| {
|
|(alias_access, inverse_alias_access)| {
|
||||||
if let Some(old) = alias_access.remove(alias.to_bytes())? {
|
if let Some(old) = alias_access.remove(alias.to_bytes())? {
|
||||||
|
@ -364,7 +362,7 @@ impl VariantAccessRepo for SledRepo {
|
||||||
let variant_access = self.variant_access.clone();
|
let variant_access = self.variant_access.clone();
|
||||||
let inverse_variant_access = self.inverse_variant_access.clone();
|
let inverse_variant_access = self.inverse_variant_access.clone();
|
||||||
|
|
||||||
let res = actix_rt::task::spawn_blocking(move || {
|
let res = crate::sync::spawn_blocking(move || {
|
||||||
(&variant_access, &inverse_variant_access).transaction(
|
(&variant_access, &inverse_variant_access).transaction(
|
||||||
|(variant_access, inverse_variant_access)| {
|
|(variant_access, inverse_variant_access)| {
|
||||||
if let Some(old) = variant_access.insert(&key, &value_bytes)? {
|
if let Some(old) = variant_access.insert(&key, &value_bytes)? {
|
||||||
|
@ -434,7 +432,7 @@ impl VariantAccessRepo for SledRepo {
|
||||||
let variant_access = self.variant_access.clone();
|
let variant_access = self.variant_access.clone();
|
||||||
let inverse_variant_access = self.inverse_variant_access.clone();
|
let inverse_variant_access = self.inverse_variant_access.clone();
|
||||||
|
|
||||||
let res = actix_rt::task::spawn_blocking(move || {
|
let res = crate::sync::spawn_blocking(move || {
|
||||||
(&variant_access, &inverse_variant_access).transaction(
|
(&variant_access, &inverse_variant_access).transaction(
|
||||||
|(variant_access, inverse_variant_access)| {
|
|(variant_access, inverse_variant_access)| {
|
||||||
if let Some(old) = variant_access.remove(&key)? {
|
if let Some(old) = variant_access.remove(&key)? {
|
||||||
|
@ -678,7 +676,7 @@ impl QueueRepo for SledRepo {
|
||||||
let queue = self.queue.clone();
|
let queue = self.queue.clone();
|
||||||
let job_state = self.job_state.clone();
|
let job_state = self.job_state.clone();
|
||||||
|
|
||||||
let res = actix_rt::task::spawn_blocking(move || {
|
let res = crate::sync::spawn_blocking(move || {
|
||||||
(&queue, &job_state).transaction(|(queue, job_state)| {
|
(&queue, &job_state).transaction(|(queue, job_state)| {
|
||||||
let state = JobState::pending();
|
let state = JobState::pending();
|
||||||
|
|
||||||
|
@ -705,7 +703,7 @@ impl QueueRepo for SledRepo {
|
||||||
.write()
|
.write()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.entry(queue_name)
|
.entry(queue_name)
|
||||||
.or_insert_with(|| Arc::new(Notify::new()))
|
.or_insert_with(crate::sync::notify)
|
||||||
.notify_one();
|
.notify_one();
|
||||||
|
|
||||||
metrics_guard.disarm();
|
metrics_guard.disarm();
|
||||||
|
@ -728,7 +726,7 @@ impl QueueRepo for SledRepo {
|
||||||
let job_state = self.job_state.clone();
|
let job_state = self.job_state.clone();
|
||||||
|
|
||||||
let span = tracing::Span::current();
|
let span = tracing::Span::current();
|
||||||
let opt = actix_rt::task::spawn_blocking(move || {
|
let opt = crate::sync::spawn_blocking(move || {
|
||||||
let _guard = span.enter();
|
let _guard = span.enter();
|
||||||
// Job IDs are generated with Uuid version 7 - defining their first bits as a
|
// Job IDs are generated with Uuid version 7 - defining their first bits as a
|
||||||
// timestamp. Scanning a prefix should give us jobs in the order they were queued.
|
// timestamp. Scanning a prefix should give us jobs in the order they were queued.
|
||||||
|
@ -802,9 +800,7 @@ impl QueueRepo for SledRepo {
|
||||||
notify
|
notify
|
||||||
} else {
|
} else {
|
||||||
let mut guard = self.queue_notifier.write().unwrap();
|
let mut guard = self.queue_notifier.write().unwrap();
|
||||||
let entry = guard
|
let entry = guard.entry(queue_name).or_insert_with(crate::sync::notify);
|
||||||
.entry(queue_name)
|
|
||||||
.or_insert_with(|| Arc::new(Notify::new()));
|
|
||||||
Arc::clone(entry)
|
Arc::clone(entry)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -823,7 +819,7 @@ impl QueueRepo for SledRepo {
|
||||||
|
|
||||||
let job_state = self.job_state.clone();
|
let job_state = self.job_state.clone();
|
||||||
|
|
||||||
actix_rt::task::spawn_blocking(move || {
|
crate::sync::spawn_blocking(move || {
|
||||||
if let Some(state) = job_state.get(&key)? {
|
if let Some(state) = job_state.get(&key)? {
|
||||||
let new_state = JobState::running(worker_id);
|
let new_state = JobState::running(worker_id);
|
||||||
|
|
||||||
|
@ -853,7 +849,7 @@ impl QueueRepo for SledRepo {
|
||||||
let queue = self.queue.clone();
|
let queue = self.queue.clone();
|
||||||
let job_state = self.job_state.clone();
|
let job_state = self.job_state.clone();
|
||||||
|
|
||||||
let res = actix_rt::task::spawn_blocking(move || {
|
let res = crate::sync::spawn_blocking(move || {
|
||||||
(&queue, &job_state).transaction(|(queue, job_state)| {
|
(&queue, &job_state).transaction(|(queue, job_state)| {
|
||||||
queue.remove(&key[..])?;
|
queue.remove(&key[..])?;
|
||||||
job_state.remove(&key[..])?;
|
job_state.remove(&key[..])?;
|
||||||
|
@ -1112,7 +1108,7 @@ impl HashRepo for SledRepo {
|
||||||
None => (self.hashes_inverse.iter(), None),
|
None => (self.hashes_inverse.iter(), None),
|
||||||
};
|
};
|
||||||
|
|
||||||
actix_rt::task::spawn_blocking(move || {
|
crate::sync::spawn_blocking(move || {
|
||||||
let page_iter = page_iter
|
let page_iter = page_iter
|
||||||
.keys()
|
.keys()
|
||||||
.rev()
|
.rev()
|
||||||
|
@ -1164,7 +1160,7 @@ impl HashRepo for SledRepo {
|
||||||
let page_iter = self.hashes_inverse.range(..=date_nanos);
|
let page_iter = self.hashes_inverse.range(..=date_nanos);
|
||||||
let prev_iter = Some(self.hashes_inverse.range(date_nanos..));
|
let prev_iter = Some(self.hashes_inverse.range(date_nanos..));
|
||||||
|
|
||||||
actix_rt::task::spawn_blocking(move || {
|
crate::sync::spawn_blocking(move || {
|
||||||
let page_iter = page_iter
|
let page_iter = page_iter
|
||||||
.keys()
|
.keys()
|
||||||
.rev()
|
.rev()
|
||||||
|
@ -1292,7 +1288,7 @@ impl HashRepo for SledRepo {
|
||||||
|
|
||||||
let hash_variant_identifiers = self.hash_variant_identifiers.clone();
|
let hash_variant_identifiers = self.hash_variant_identifiers.clone();
|
||||||
|
|
||||||
actix_rt::task::spawn_blocking(move || {
|
crate::sync::spawn_blocking(move || {
|
||||||
hash_variant_identifiers
|
hash_variant_identifiers
|
||||||
.compare_and_swap(key, Option::<&[u8]>::None, Some(value.as_bytes()))
|
.compare_and_swap(key, Option::<&[u8]>::None, Some(value.as_bytes()))
|
||||||
.map(|res| res.map_err(|_| VariantAlreadyExists))
|
.map(|res| res.map_err(|_| VariantAlreadyExists))
|
||||||
|
|
|
@ -34,9 +34,7 @@ macro_rules! b {
|
||||||
($self:ident.$ident:ident, $expr:expr) => {{
|
($self:ident.$ident:ident, $expr:expr) => {{
|
||||||
let $ident = $self.$ident.clone();
|
let $ident = $self.$ident.clone();
|
||||||
|
|
||||||
let span = tracing::Span::current();
|
crate::sync::spawn_blocking(move || $expr)
|
||||||
|
|
||||||
actix_rt::task::spawn_blocking(move || span.in_scope(|| $expr))
|
|
||||||
.await
|
.await
|
||||||
.map_err(SledError::from)
|
.map_err(SledError::from)
|
||||||
.map_err(RepoError::from)?
|
.map_err(RepoError::from)?
|
||||||
|
|
|
@ -277,7 +277,7 @@ impl Store for ObjectStore {
|
||||||
|
|
||||||
let object_id2 = object_id.clone();
|
let object_id2 = object_id.clone();
|
||||||
let upload_id2 = upload_id.clone();
|
let upload_id2 = upload_id.clone();
|
||||||
let handle = actix_rt::spawn(
|
let handle = crate::sync::spawn(
|
||||||
async move {
|
async move {
|
||||||
let response = this
|
let response = this
|
||||||
.create_upload_part_request(
|
.create_upload_part_request(
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use actix_rt::{task::JoinHandle, time::Sleep};
|
use actix_rt::{task::JoinHandle, time::Sleep};
|
||||||
use actix_web::web::Bytes;
|
use actix_web::web::Bytes;
|
||||||
|
use flume::r#async::RecvStream;
|
||||||
use futures_core::Stream;
|
use futures_core::Stream;
|
||||||
use std::{
|
use std::{
|
||||||
future::Future,
|
future::Future,
|
||||||
|
@ -174,19 +175,25 @@ pin_project_lite::pin_project! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum IterStreamState<I, T> {
|
enum IterStreamState<I, T>
|
||||||
|
where
|
||||||
|
T: 'static,
|
||||||
|
{
|
||||||
New {
|
New {
|
||||||
iterator: I,
|
iterator: I,
|
||||||
buffer: usize,
|
buffer: usize,
|
||||||
},
|
},
|
||||||
Running {
|
Running {
|
||||||
handle: JoinHandle<()>,
|
handle: JoinHandle<()>,
|
||||||
receiver: tokio::sync::mpsc::Receiver<T>,
|
receiver: RecvStream<'static, T>,
|
||||||
},
|
},
|
||||||
Pending,
|
Pending,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct IterStream<I, T> {
|
pub(crate) struct IterStream<I, T>
|
||||||
|
where
|
||||||
|
T: 'static,
|
||||||
|
{
|
||||||
state: IterStreamState<I, T>,
|
state: IterStreamState<I, T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -287,14 +294,13 @@ where
|
||||||
|
|
||||||
match std::mem::replace(&mut this.state, IterStreamState::Pending) {
|
match std::mem::replace(&mut this.state, IterStreamState::Pending) {
|
||||||
IterStreamState::New { iterator, buffer } => {
|
IterStreamState::New { iterator, buffer } => {
|
||||||
let (sender, receiver) = tracing::trace_span!(parent: None, "Create channel")
|
let (sender, receiver) = crate::sync::channel(buffer);
|
||||||
.in_scope(|| tokio::sync::mpsc::channel(buffer));
|
|
||||||
|
|
||||||
let mut handle = actix_rt::task::spawn_blocking(move || {
|
let mut handle = crate::sync::spawn_blocking(move || {
|
||||||
let iterator = iterator.into_iter();
|
let iterator = iterator.into_iter();
|
||||||
|
|
||||||
for item in iterator {
|
for item in iterator {
|
||||||
if sender.blocking_send(item).is_err() {
|
if sender.send(item).is_err() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -304,14 +310,17 @@ where
|
||||||
return Poll::Ready(None);
|
return Poll::Ready(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.state = IterStreamState::Running { handle, receiver };
|
this.state = IterStreamState::Running {
|
||||||
|
handle,
|
||||||
|
receiver: receiver.into_stream(),
|
||||||
|
};
|
||||||
|
|
||||||
self.poll_next(cx)
|
self.poll_next(cx)
|
||||||
}
|
}
|
||||||
IterStreamState::Running {
|
IterStreamState::Running {
|
||||||
mut handle,
|
mut handle,
|
||||||
mut receiver,
|
mut receiver,
|
||||||
} => match Pin::new(&mut receiver).poll_recv(cx) {
|
} => match Pin::new(&mut receiver).poll_next(cx) {
|
||||||
Poll::Ready(Some(item)) => {
|
Poll::Ready(Some(item)) => {
|
||||||
this.state = IterStreamState::Running { handle, receiver };
|
this.state = IterStreamState::Running { handle, receiver };
|
||||||
|
|
||||||
|
|
38
src/sync.rs
Normal file
38
src/sync.rs
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use tokio::sync::{Notify, Semaphore};
|
||||||
|
|
||||||
|
pub(crate) fn channel<T>(bound: usize) -> (flume::Sender<T>, flume::Receiver<T>) {
|
||||||
|
tracing::trace_span!(parent: None, "make channel").in_scope(|| flume::bounded(bound))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn notify() -> Arc<Notify> {
|
||||||
|
Arc::new(bare_notify())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn bare_notify() -> Notify {
|
||||||
|
tracing::trace_span!(parent: None, "make notifier").in_scope(Notify::new)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn bare_semaphore(permits: usize) -> Semaphore {
|
||||||
|
tracing::trace_span!(parent: None, "make semaphore").in_scope(|| Semaphore::new(permits))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn spawn<F>(future: F) -> actix_rt::task::JoinHandle<F::Output>
|
||||||
|
where
|
||||||
|
F: std::future::Future + 'static,
|
||||||
|
F::Output: 'static,
|
||||||
|
{
|
||||||
|
tracing::trace_span!(parent: None, "spawn task").in_scope(|| actix_rt::spawn(future))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn spawn_blocking<F, Out>(function: F) -> actix_rt::task::JoinHandle<Out>
|
||||||
|
where
|
||||||
|
F: FnOnce() -> Out + Send + 'static,
|
||||||
|
Out: Send + 'static,
|
||||||
|
{
|
||||||
|
let outer_span = tracing::Span::current();
|
||||||
|
|
||||||
|
tracing::trace_span!(parent: None, "spawn blocking task")
|
||||||
|
.in_scope(|| actix_rt::task::spawn_blocking(move || outer_span.in_scope(function)))
|
||||||
|
}
|
|
@ -13,8 +13,7 @@ struct TmpFile(PathBuf);
|
||||||
|
|
||||||
impl Drop for TmpFile {
|
impl Drop for TmpFile {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
tracing::trace_span!(parent: None, "Spawn task")
|
crate::sync::spawn(tokio::fs::remove_file(self.0.clone()));
|
||||||
.in_scope(|| actix_rt::spawn(tokio::fs::remove_file(self.0.clone())));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue