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

Don't obscure errors during migrations #577

Merged

Conversation

matthewmcgarvey
Copy link
Member

@matthewmcgarvey matthewmcgarvey commented Dec 26, 2020

Fixes #422

While the errors might look "uglier", they will now definitely contain the error message and the stacktrace.

Instead of dropping exceptions for new messages with a new stacktrace, this raises a new error with the original error as the cause so that we can add info without forgetting context. The only problem was that Crystal does not print the "cause" of unhandled exceptions (source). To overcome this, I updated Avram::Migrator to print the error so that we can get the cause and then to exit so that it's still recognized as a failure.

Copy link
Member

@jwoertink jwoertink left a comment

Choose a reason for hiding this comment

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

Just the one comment, but I think the rest is good to go. I'm also noticing the interface for these tasks are a bit inconsistent. Like some run and then do a puts, but others don't. Another PR for another time 😂

@@ -96,16 +96,6 @@ abstract class Avram::Migrator::Migration::V1
yield tx
end
end
rescue e : PQ::PQError
Copy link
Member

Choose a reason for hiding this comment

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

Any idea if the actual stack trace will include the statement that failed? I'm wondering if instead of removing this one, we just figure out how to add the filename to it. I'm worried letting it error on its own wouldn't really provide that nice of an error.

Copy link
Member Author

Choose a reason for hiding this comment

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

So it wouldn't. One thing I was thinking about is handling all errors that are raised from migrations, wrapping them with more information (name of migration, statement that caused it), and printing them ourselves so that we can include the cause of exceptions and then exiting as a failure. What do you think?

Copy link
Member Author

Choose a reason for hiding this comment

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

Calling https://crystal-lang.org/api/0.35.1/Exception.html#inspect_with_backtrace:String-instance-method on exceptions includes the cause, I don't know why Crystal doesn't use it in the unhandled exception code flow.

Copy link
Member

Choose a reason for hiding this comment

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

Yeah, I like that. One thing that sets us apart from others is how we display really nice error messages. Do you want to do that in this PR, or a different one? I'm cool with either way.

Copy link
Member Author

Choose a reason for hiding this comment

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

I'll update this PR. I believe this will help #578 (comment) as well

Copy link
Member Author

Choose a reason for hiding this comment

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

@jwoertink done 👍 this is much better, I think

Also wrap exceptions so that we can point to the name of the migration and the statements
This allows specs to call tasks without running into the exit code
@@ -66,7 +66,7 @@ end

describe Avram::Migrator::Migration::V1 do
it "executes statements in a transaction" do
expect_raises Exception, %(relation "table_does_not_exist" does not exist) do
expect_raises Avram::FailedMigration do
Copy link
Member Author

Choose a reason for hiding this comment

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

Can no longer assert on the message because it is in the cause, not in the expected error

raise e.message.to_s
rescue e
puts e.inspect_with_backtrace
exit 1
Copy link
Member Author

Choose a reason for hiding this comment

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

This is to be able to print the error with the cause but it means we are explicitly exit-ing in code

@@ -0,0 +1,9 @@
abstract class BaseTask < LuckyCli::Task
Copy link
Member Author

Choose a reason for hiding this comment

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

This abstract class was pulled out so that we could test and use tasks without accidentally running into the exit code.

Copy link
Member

Choose a reason for hiding this comment

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

oh nice! Good call.

@@ -3,19 +3,5 @@ require "./src/avram"
require "./config/*"
require "./db/migrations/*"

class Db::Reset < LuckyCli::Task
Copy link
Member Author

Choose a reason for hiding this comment

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

There is already a separate Db::Reset task that was overwriting this one. This was old and I noticed it while updating tasks to the new pattern

Copy link
Member

@jwoertink jwoertink left a comment

Choose a reason for hiding this comment

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

Nice! Yeah, I feel a lot better about this direction 👍

@matthewmcgarvey matthewmcgarvey merged commit f667249 into luckyframework:master Dec 28, 2020
@matthewmcgarvey matthewmcgarvey deleted the migration-errors branch December 28, 2020 21:20
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.

Migrator obscures stack trace of unhandled exceptions
2 participants