Skip to content

Commit

Permalink
Merge pull request #9598 from Turbo87/async-delete-version
Browse files Browse the repository at this point in the history
admin/delete_version: Reduce `spawn_blocking()` usage
  • Loading branch information
Turbo87 authored Oct 7, 2024
2 parents 16823fc + 9d1f7c3 commit 5b08d3d
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 29 deletions.
74 changes: 46 additions & 28 deletions src/admin/delete_version.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ use crate::tasks::spawn_blocking;
use crate::worker::jobs;
use crate::{admin::dialoguer, db, schema::versions};
use anyhow::Context;
use diesel::prelude::*;
use diesel::{Connection, ExpressionMethods, QueryDsl};
use diesel_async::async_connection_wrapper::AsyncConnectionWrapper;

#[derive(clap::Parser, Debug)]
#[command(
Expand All @@ -27,18 +28,25 @@ pub struct Opts {
}

pub async fn run(opts: Opts) -> anyhow::Result<()> {
spawn_blocking(move || {
let crate_name = &opts.crate_name;
let mut conn = db::oneoff_async_connection()
.await
.context("Failed to establish database connection")?;

let conn = &mut db::oneoff_connection().context("Failed to establish database connection")?;
let store = Storage::from_environment();

let store = Storage::from_environment();
let crate_id: i32 = {
use diesel_async::RunQueryDsl;

let crate_id: i32 = crates::table
crates::table
.select(crates::id)
.filter(crates::name.eq(crate_name))
.first(conn)
.context("Failed to look up crate id from the database")?;
.filter(crates::name.eq(&opts.crate_name))
.first(&mut conn)
.await
.context("Failed to look up crate id from the database")
}?;

{
let crate_name = &opts.crate_name;

println!("Deleting the following versions of the `{crate_name}` crate:");
println!();
Expand All @@ -47,9 +55,20 @@ pub async fn run(opts: Opts) -> anyhow::Result<()> {
}
println!();

if !opts.yes && !dialoguer::confirm("Do you want to permanently delete these versions?")? {
if !opts.yes
&& !dialoguer::async_confirm("Do you want to permanently delete these versions?")
.await?
{
return Ok(());
}
}

let opts = spawn_blocking::<_, _, anyhow::Error>(move || {
use diesel::RunQueryDsl;

let conn: &mut AsyncConnectionWrapper<_> = &mut conn.into();

let crate_name = &opts.crate_name;

conn.transaction(|conn| {
info!(%crate_name, %crate_id, versions = ?opts.versions, "Deleting versions from the database");
Expand Down Expand Up @@ -87,27 +106,26 @@ pub async fn run(opts: Opts) -> anyhow::Result<()> {
warn!(%crate_name, ?error, "Failed to enqueue index sync jobs");
}

let rt = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.context("Failed to initialize tokio runtime")?;
Ok(opts)
}).await?;

for version in &opts.versions {
debug!(%crate_name, %version, "Deleting crate file from S3");
if let Err(error) = rt.block_on(store.delete_crate_file(crate_name, version)) {
warn!(%crate_name, %version, ?error, "Failed to delete crate file from S3");
}
let crate_name = &opts.crate_name;

debug!(%crate_name, %version, "Deleting readme file from S3");
match rt.block_on(store.delete_readme(crate_name, version)) {
Err(object_store::Error::NotFound { .. }) => {}
Err(error) => {
warn!(%crate_name, %version, ?error, "Failed to delete readme file from S3")
}
Ok(_) => {}
for version in &opts.versions {
debug!(%crate_name, %version, "Deleting crate file from S3");
if let Err(error) = store.delete_crate_file(crate_name, version).await {
warn!(%crate_name, %version, ?error, "Failed to delete crate file from S3");
}

debug!(%crate_name, %version, "Deleting readme file from S3");
match store.delete_readme(crate_name, version).await {
Err(object_store::Error::NotFound { .. }) => {}
Err(error) => {
warn!(%crate_name, %version, ?error, "Failed to delete readme file from S3")
}
Ok(_) => {}
}
}

Ok(())
}).await
Ok(())
}
8 changes: 7 additions & 1 deletion src/admin/dialoguer.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
use crate::tasks::spawn_blocking;
use ::dialoguer::{theme::Theme, Confirm};

pub fn confirm(msg: &str) -> dialoguer::Result<bool> {
pub async fn async_confirm(msg: impl Into<String>) -> anyhow::Result<bool> {
let msg = msg.into();
spawn_blocking(move || confirm(msg).map_err(anyhow::Error::from)).await
}

pub fn confirm(msg: impl Into<String>) -> dialoguer::Result<bool> {
Confirm::with_theme(&CustomTheme)
.with_prompt(msg)
.default(false)
Expand Down

0 comments on commit 5b08d3d

Please sign in to comment.