Skip to content

Commit

Permalink
Add option to cancel jobs. Fixes #17
Browse files Browse the repository at this point in the history
  • Loading branch information
gsleap committed Nov 22, 2024
1 parent a60ad3d commit b8015bb
Show file tree
Hide file tree
Showing 5 changed files with 188 additions and 4 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Versioning](https://semver.org/spec/v2.0.0.html).

## 1.2.0 - 2024-10-08

* NEW FEATURE- added `cancel` command to allow cancellation of in progress jobs.
* Updated/migrated clap to v4.4.
* Updated dependency quinn-proto to latest to fix security vulnerability.
* BUGFIX- the alias "sv" was assigned to both "submit-vis" and "submit-volt". "st" has now been assigned for "submit-volt" to avoid the duplication.
Expand Down
4 changes: 2 additions & 2 deletions src/asvo/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,11 @@ pub enum AsvoError {
#[error("MWA_ASVO_API_KEY is not defined.")]
MissingAuthKey,

/// The response had a status code other than 200.
/// The response had a status code other than "known" http status codes.
#[error("The server responded with status code {code}, message:\n{message}")]
BadStatus { code: StatusCode, message: String },

/// The response indicates a bad request.
/// The response indicates a bad request (400).
#[error("The server responded with status code {code}, message:\n{message}")]
BadRequest { code: u32, message: String },

Expand Down
87 changes: 87 additions & 0 deletions src/asvo/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,52 @@ impl AsvoClient {
}
}
}

/// This low-level function actually cancels a job.
/// The return can either be:
/// Ok(job_id) - this is when an existing job is successfully cancelled
/// Ok(None) - this is when it failed but it's ok to continue
/// Err() - this is when we hit an error
pub fn cancel_asvo_job(&self, job_id: u32) -> Result<Option<u32>, AsvoError> {
debug!("Cancelling an MWA ASVO job");

let mut form: BTreeMap<&str, &str> = BTreeMap::new();
let job_id_str = format!("{}", job_id);
form.insert("job_id", &job_id_str);

// Send a GET(?) request to the MWA ASVO.
// Should be POST!
let response = self
.client
.get(format!(
"{}/api/{}?job_id={}",
get_asvo_server_address(),
"cancel_job",
job_id
))
.send()?;

let status_code = response.status();
let response_text = &response.text()?;
if status_code == 200 {
Ok(Some(job_id))
} else if status_code == 400 {
// Validation error
warn!("{}", &response_text);
Ok(None)
} else if status_code == 404 {
// Job id not found
warn!("Job Id: {} not found", job_id);
Ok(None)
} else {
// Show the http code when it's not something we can handle
warn!("http code: {} response: {}", status_code, &response_text);
return Err(AsvoError::BadStatus {
code: status_code,
message: response_text.to_string(),
});
}
}
}

#[cfg(test)]
Expand Down Expand Up @@ -671,6 +717,47 @@ mod tests {
}
}

#[test]
fn test_cancel_job_not_found() {
let job_id = 1234;
let client = AsvoClient::new().unwrap();
let cancel_result = client.cancel_asvo_job(job_id);

assert!(cancel_result.is_ok_and(|j| j.is_none()))
}

#[test]
fn test_cancel_job_successful() {
let client = AsvoClient::new().unwrap();

// submit a new job (don't worry we will cancel it right away)
let obs_id = Obsid::validate(1416257384).unwrap();
let delivery = Delivery::Acacia;
let delivery_format: Option<DeliveryFormat> = None;
let allow_resubmit: bool = false;
let meta_job = client.submit_vis(obs_id, delivery, delivery_format, allow_resubmit);

let new_job_id: u32;

match meta_job {
Ok(job_id_or_none) => match job_id_or_none {
Some(j) => new_job_id = j,
None => panic!("Job submitted, but no jobid returned?"),
},
Err(error) => match error {
AsvoError::BadStatus {
code: c,
message: m,
} => panic!("Error has occurred: {} {}", c, m),
_ => panic!("Unexpected error has occured."),
},
}

let cancel_result = client.cancel_asvo_job(new_job_id);

assert!(cancel_result.is_ok_and(|j| j.unwrap() == new_job_id))
}

#[test]
fn test_submit_vis_as_tar() {
let client = AsvoClient::new().unwrap();
Expand Down
59 changes: 57 additions & 2 deletions src/bin/giant-squid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use mwa_giant_squid::*;

const ABOUT: &str = r#"An alternative, efficient and easy-to-use MWA ASVO client.
Source: https://github.com/MWATelescope/giant-squid
MWA ASVO: https://asvo.mwatelescope.org"#;
MWA ASVO:"#;

lazy_static::lazy_static! {
static ref DEFAULT_CONVERSION_PARAMETERS_TEXT: String = {
Expand Down Expand Up @@ -293,6 +293,25 @@ enum Args {
#[arg(id = "JOB")]
jobs: Vec<String>,
},

/// Cancel MWA ASVO job
#[command(alias = "c")]
Cancel {
/// Don't actually cancel; print information on what would've happened
/// instead.
#[arg(short = 'n', long)]
dry_run: bool,

/// The verbosity of the program. The default is to print high-level
/// information.
#[arg(short, long, action=ArgAction::Count)]
verbosity: u8,

/// The jobs to be cancelled. Files containing obsids are also
/// accepted.
#[arg(id = "JOB")]
jobs: Vec<String>,
},
}

fn init_logger(level: u8) {
Expand Down Expand Up @@ -737,7 +756,7 @@ fn main() -> Result<(), anyhow::Error> {
} => {
let (parsed_jobids, _) = parse_many_jobids_or_obsids(&jobs)?;
if parsed_jobids.is_empty() {
bail!("No obsids specified!");
bail!("No jobids specified!");
}
init_logger(verbosity);
let client = AsvoClient::new()?;
Expand All @@ -756,6 +775,42 @@ fn main() -> Result<(), anyhow::Error> {
jobs.list();
}
}

Args::Cancel {
dry_run,
verbosity,
jobs,
} => {
let (parsed_jobids, _) = parse_many_jobids_or_obsids(&jobs)?;
if parsed_jobids.is_empty() {
bail!("No jobids specified!");
}
init_logger(verbosity);

if dry_run {
info!("Would have cancelled {} jobids.", parsed_jobids.len());
} else {
let client = AsvoClient::new()?;

let mut cancelled_count = 0;
for j in parsed_jobids {
let result = client.cancel_asvo_job(j);

if result.is_ok() {
let success = result.unwrap();

// Job was cancelled.
// None means it was not cancelled but don't stop
// processing the rest of the list
if success.is_some() {
info!("Cancelled ASVO job ID {}", j);
cancelled_count += 1;
}
}
}
info!("Cancelled {} jobs.", cancelled_count);
}
}
}

Ok(())
Expand Down
41 changes: 41 additions & 0 deletions tools/test_msrv.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#!/usr/bin/env bash

# Fail the script on any error
set -e

#
# This is a helper script so that when giant-squid is ready to be
# released, this can check to ensure that it works in the
# minimum Rust version (MSRV) as specified in Cargo.toml
#
# It assumes:
# 1. You run this from inside the "tools" directory
# 2. You have rustup installed
#

# Switch to the root giant-squid dir
pushd ..

# update rust
echo "Updating rust..."
rustup update

# Ensure MSRV version of rust is installed
MIN_RUST=$(grep -m1 "rust-version" Cargo.toml | sed 's|.*\"\(.*\)\"|\1|')
echo "Installing MSRV ${MIN_RUST}..."
rustup install ${MIN_RUST}

# Clear everything
cargo clean
rm -rf target

# Update dependencies
echo "Updating cargo dependencies..."
RUSTUP_TOOLCHAIN=${MIN_RUST} cargo update --verbose

# Build and run rust tests
echo "Building and running tests..."
RUSTUP_TOOLCHAIN=${MIN_RUST} cargo test --release --all-features

# Switch back to this dir
popd

0 comments on commit b8015bb

Please sign in to comment.