Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change cli to propagate error to exit code #8856

Merged
merged 8 commits into from
Jan 16, 2024

Conversation

tshauck
Copy link
Contributor

@tshauck tshauck commented Jan 13, 2024

Which issue does this PR close?

TODO:

Rationale for this change

The rationale is that currently when using the cli, if you use -c and -f, both of which are useful to use datafusion in workflows (e.g. and ETL pipeline), the exit code if the query fails is still 0. Most job orchestration tools can propagate the exit code from a CLI tool "up", so this makes using the CLI more ergonomic for that use case.

What changes are included in this PR?

Generally, adds Result return enums so that the CLI will eventually return the 0 or 1 exit code to the caller.

Are these changes tested?

I ran the -c, -f, and interactive mode. Things are functional, though the main difference I've noticed is the error printed out is a bit more verbose right now. E.g.

./target/debug/datafusion-cli -c 'SELECT hi';        
DataFusion CLI v34.0.0
Error: SchemaError(FieldNotFound { field: Column { relation: None, name: "hi" }, valid_fields: [] }, Some(""))

echo $?;
1

If this is to be merged, I'll try to cleanup the error message, but I thought I'd open this to get feedback as to if this is something the project would consider merging.

Thanks

@tshauck tshauck marked this pull request as draft January 14, 2024 17:07
Copy link
Contributor

@alamb alamb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes a lot of sense to me @tshauck -- thank you 🙏

@tshauck
Copy link
Contributor Author

tshauck commented Jan 15, 2024

Thanks @alamb... so looking into the error display, it looks like the printed message is Debug. So certainly, open to alternatives, but what I did to start is implement a new DataFusionCLIError where Debug and Display just show an inner message. It also implements From for datafusion error and rustyline error so they can be transformed into the new error.

With those changes, this is what the error now looks like:

./target/debug/datafusion-cli -c 'SELECT hi;'               
DataFusion CLI v34.0.0
Error: Schema error: No field named hi.

@tshauck tshauck marked this pull request as ready for review January 15, 2024 01:49
@tshauck tshauck requested a review from alamb January 15, 2024 01:50
Copy link
Contributor

@alamb alamb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @tshauck

@@ -138,7 +139,7 @@ struct Args {
}

#[tokio::main]
pub async fn main() -> Result<()> {
pub async fn main() -> Result<(), DataFusionCLIError> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than implementing an entire new error class just to reuse the existing error handler, what do you think about handling the error explicitly? Perhaps something like

#[tokio::main]
/// Handle errors in `main_inner`
pub async fn main() {
 // print nice error and return error status from process on error
  if let Err(e) = main_inner().await {
    println!("Execution Error: {e}");
    std::process:exit(1);
  }
}

/// Main CLI entrypoint
async fn main_inner() -> Result<()> {
    env_logger::init();
    let args = Args::parse();
...
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Works for me too... I'll take another crack at it this evening and follow up when it's ready.

Copy link
Contributor Author

@tshauck tshauck Jan 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I ended up going a slightly different route and wrapped main as suggested but am having it return ExitCode vs ().

From the std::process::exit docs, it seems like while it can work, it's preferable to either return Result (initial impl if verbose) or ExitCode (i.e. something that implements Termination) to better handle cleanup, not that it matters a ton here, but 🤷 .

Note that because this function never returns, and that it terminates the process, no destructors on the current stack or any other thread’s stack will be run. If a clean shutdown is needed it is recommended to only call this function at a known point where there are no more destructors left to run; or, preferably, simply return a type implementing Termination (such as ExitCode or Result) from the main function and avoid this function altogether:

https://doc.rust-lang.org/std/process/fn.exit.html

Happy to go w/ exit if you still think it's the best route.

@tshauck tshauck requested a review from alamb January 15, 2024 21:47
Copy link
Contributor

@alamb alamb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me -- thank you @tshauck

@@ -138,7 +139,18 @@ struct Args {
}

#[tokio::main]
pub async fn main() -> Result<()> {
/// Calls [`main_inner`], then handles printing errors and returning the correct exit code
pub async fn main() -> ExitCode {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@alamb
Copy link
Contributor

alamb commented Jan 16, 2024

I also double checked with a quick test locally:

venv) andrewlamb@Andrews-MacBook-Pro:~/Software/arrow-datafusion/datafusion-cli$ ./target/debug/datafusion-cli  -c 'select foo()' || echo "fail"
DataFusion CLI v34.0.0
Error: Error during planning: Invalid function 'foo'.
Did you mean 'cos'?
fail
(venv) andrewlamb@Andrews-MacBook-Pro:~/Software/arrow-datafusion/datafusion-cli$ ./target/debug/datafusion-cli  -c 'select 1' || echo "fail"
DataFusion CLI v34.0.0
+----------+
| Int64(1) |
+----------+
| 1        |
+----------+
1 row in set. Query took 0.014 seconds.

And it seems to work great. Thanks @tshauck !

@alamb alamb merged commit 5433b52 into apache:main Jan 16, 2024
22 checks passed
@tshauck tshauck deleted the change-cli-to-propagate-error branch January 16, 2024 13:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants