-
Notifications
You must be signed in to change notification settings - Fork 304
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
Throw exception / error on unsuccessful execution run #891
Comments
I'd love to see a solution for this in Robo. I think it might need to go beyond just a flag, to something where commands throw an exception by default. Otherwise it doesn't really solve the problem BLT is facing, which is that we'd like for commands to handle errors conservatively (i.e. throw an exception) by default, rather than forcing developers to remember to check exit codes every time they run a command. It's awfully hard for downstream projects to work around this problem. Here's BLT's WIP that I'm half tempted to abandon due to the shear complexity: acquia/blt#3839 @greg-1-anderson I'd love to hear your thoughts on this issue. Do you think the request, or at least BLT's problem statement of trying to avoid uncaught errors, makes sense? Would you propose an alternative solution, or a cleaner workaround than what we've started in the PR? I'm happy to put in some legwork if we can reach consensus on a solution. |
I think that throwing exceptions by default might be the right thing to do for Robo 2.x. I am -1 on having a bunch of flags like The one question about throw by default is, how do scripts respond if they want to catch a failure? Throw is undoubtably best for clients using Robo as a framework, but Robo's roots lie in simple scripts that work reliably, and are still easy to read (not a lot of nesting with conditionals and try / catch). This can evolve as Robo 2 develops. I'm spending a lot of time on Composer In Core initiative right now, but I would like to make it easier to define tasks in Robo 2 that execute in sequence (e.g. in a collection), but can still pass values from one step to the next using a promise-like object. Perhaps an exception handling model can fit into this development. |
I figured that projects implementing Robo would just use try/catch. So for tasks that should exit on error: // Robo 1.x
$result = $this->taskExecStack()
->exec("do something that should exit on error")
->run();
if (!$result->wasSuccessful()) {
throw new Exception("Task failed!")
}
// Robo 2.x
$this->taskExecStack()
->exec("do something that should exit on error")
->run(); I suspect this use case is most common, and it becomes much simpler and safer in the new paradigm. To your point about excessive conditionals and such, this actually helps the situation. For commands that should not exit on error: // Robo 1.x
$result = $this->taskExecStack()
->exec("do something that should not exit on error")
->run();
if (!$result->wasSuccessful()) {
// Do something intelligent here to recover or throw error.
}
// Robo 2.x
try {
$this->taskExecStack()
->exec("do something that should not exit on error")
->run();
}
catch (RoboException $e) {
// $e contains the result including exit code.
// Do something intelligent here to recover or throw error.
} This is only moderately more complex, and somewhat less common I suspect. Another option to get this into Robo 1.x without affecting backwards compatibility would be to add a flag to the Robo container itself that persists for all commands, i.e. |
I wanted to avoid having folks have to put try / catch in their scripts to recover from errors. Robo 2.x idea. Throws an exception on error (caught by application, which exits):
Does not throw an exception on error:
The way this works is that The So, you have the choice of whether to throw or not depending on how you run your tasks. If this is a little too magical, then perhaps the different forms of I am also thinking that I can make this work:
That is, Again, there's a trade off between having magical things happening in the task runner vs. having to do a lot of error checking throughout the script. Folks are going to tend to leave off the For a framework-type application, I think that having a lot of explicit error checking / catch blocks is best. For a task runner, though, I think think that there's benefit to keeping the scripts easy to write and easy to read without making them brittle e.g. if a failed step is not checked and execution continues. That's why Robo 0.6 had the whole |
That's pretty clever, I do like the idea of maintaining the "old" style checking of return objects rather than using try/catch. I agree that try/catch is a bit ugly, but I'm probably biased because I grew up writing PHP instead of... I don't know, just about any other programming language? :) I agree it feels a bit magical, I might need to think about it more to have a strong opinion on whether it's too magical, and honestly to grok everything happening with the promises. It sounds like we are on the same page that the priority is making it easy to implement Robo tasks in a (usually) safe way, without having to remember a bunch of flags and patterns such as Tangentially, I discovered that we were using |
I don't use By default, collections always stop if one of the tasks in them fails. |
Just so. But my point was just that the name is confusing, in the theme of having to remember what flags to use and what they do, how to do error handling consistently, etc... |
I didn't find any documentation on error handling thus far that's why I'd propose the following:
Add a new flag called
throwErrorOnFail
to theCommandStack
, so that there's a way to configure that the code stops execution after a failed execution (result was unsuccessful).This is helpful to avoid running any code after a command previously failed.
The text was updated successfully, but these errors were encountered: