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

Add one_email_per_occurrence option and migration task #53

Open
wants to merge 21 commits into
base: main
Choose a base branch
from

Conversation

imageaid
Copy link

@imageaid imageaid commented Jul 17, 2024

Motivation:

We are happily using Solid Errors in our production app but because that app connects to some external APIs we can run into situations where we are sent a lot of emails for the same error's reoccurrence.

Details:

Introduced a new configuration option one_email_per_occurrence that serves to limit email notifications to one per occurrence. If an error is resolved but reoccurs, an email will be sent, again, for that first reoccurrence.

In order to do this, a migration was created to add a new column/attribute to the solid_errors table called prev_resolved_at.

This column/attribute is updated to match the resolved_at value whenever it is set - but it is never nill'ed out like resolved_at is when the issue is resolved.

A Rake task, solid_errors:install_migrations, was also added to copy any new migrations from the lib/solid_errors/db/migrate directory and then immediately run them.

The README was updated as was the error controller to support the new feature.

The .gemspec was also updated to add a note reminding users to ensure they've run the task to copy over the migration(s).

Please let me know if there's anything you'd change, do better, etc. Thank you for your excellent work on Solid Errors. We are grateful to have it!

Introduce the one_email_per_occurrence configuration option to limit email notifications to one per occurrence. Updated README and error controller to support the new feature, and added Rake task to handle migrations.
@fractaledmind fractaledmind self-requested a review July 18, 2024 09:04
Copy link
Owner

@fractaledmind fractaledmind left a comment

Choose a reason for hiding this comment

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

I like this! Thanks for such a clear and thorough PR. I've made a few comments for things to tweak to get it over the line.

app/models/solid_errors/occurrence.rb Outdated Show resolved Hide resolved
app/models/solid_errors/occurrence.rb Outdated Show resolved Hide resolved
app/models/solid_errors/occurrence.rb Outdated Show resolved Hide resolved
app/views/solid_errors/errors/_actions.html.erb Outdated Show resolved Hide resolved
lib/tasks/solid_errors_tasks.rake Outdated Show resolved Hide resolved
app/models/solid_errors/occurrence.rb Outdated Show resolved Hide resolved
@imageaid
Copy link
Author

I like this! Thanks for such a clear and thorough PR. I've made a few comments for things to tweak to get it over the line.

Thank you so much for taking the time to review this and to add all your helpful edits and comments. Much much appreciated!

I am not sure if you need me to/if I should make some commits in my branch and redo my PR (this is my first PR to a gem so please forgive any stupidity or missteps on my part!).

Thanks, again, so much for your work. Please know how much my team appreciates Solid Errors!

@fractaledmind
Copy link
Owner

fractaledmind commented Jul 18, 2024

Yeah, you've done such a great job with the PR that I'd like you to finish it yourself and have full credit!

@imageaid
Copy link
Author

Yeah, you've done such a great job with the PR that is like you to finish it yourself and have full credit!

AWESOME! Man, really appreciate it. I will make the changes and commit them shortly

- Converted prev_resolved_at to a datetime from a timestamp in migration
- Added a method `should_send_email?` to determine if an email goes instead of a string of conditionals
- Cleaned up guard clauses
- Improved the datetime comparison in an AR query
The refactor involved removing a segment which forced a specific migration to run in favor of Rails' mechanism of alerting when migrations are pending. The prior method was too rigid and hard-coded. Now, the system still copies the migration over but doesn't automatically run it.
The 'prev_resolved_at' parameter has been removed from the error_params in the errors_controller, and subsequently from the error buttons in the views. Meanwhile, in the subscriber, 'prev_resolved_at' is now updated with the current 'resolved_at' before this is set to nil, maintaining the history of resolution times.
@imageaid
Copy link
Author

imageaid commented Jul 18, 2024

For the prev_resolved_at, I just made a commit that might be a better way? Let me know your thoughts.

Basically, I removed that element from the buttons in the _action and _row view files as well as the controller. Instead, I set it in the Subscriber just before the resolved_at value is nilled out.

Maybe less intrusive and more seamless?

Totally open to other alternatives of course!

Finally, for the migration, I just kept the rake task the same in terms of copying the migration files over. But, I killed the running of them (I have some commented out code as an alternative approach to run just the specific migration if desired) because Rails will, of course, scream and yell at us that we have pending migrations to run ... duh on my part 🤣

README.md Outdated Show resolved Hide resolved
Simplified the condition check whether to send an email in SolidErrors::Occurrence. The method should_send_email? now has guard clauses if SolidErrors does not send emails or if no email recipient is set. Additionally, the instance method one_email_per_occurrence is renamed to one_email_per_occurrence? to follow the naming convention like `send_emails?`.
solid_errors.gemspec Outdated Show resolved Hide resolved
The config option that limits the email notifications to one email per error occurrence in the SolidErrors has been removed and, instead, that approach is used automatically (sending one per occurrence). Corrections were also made to the post-install message in the gemspec file to remove the ``*and* runs` from the note since we are not auto-running migrations.
@fractaledmind
Copy link
Owner

We still need a note in the README explaining the behavior for email sending

@imageaid
Copy link
Author

We still need a note in the README explaining the behavior for email sending

Just pushed a commit with an edited note about sending emails. Let me know if you think that fits the bill or needs some added massaging, etc.

app/models/solid_errors/occurrence.rb Outdated Show resolved Hide resolved
lib/tasks/solid_errors_tasks.rake Outdated Show resolved Hide resolved
…ng process

In the 'Occurrence' model, the condition checking if an error has only one occurrence has been simplified by replacing 'count == 1' with 'one?'. In the rake task, the file copying process from Solid Errors to Rails application has been altered so that instead of copying the file directly, it's named with a timestamp before copying to avoid potential naming conflicts. The migration file name was also simplified by removing the timestamp so that we can dynamically add one.
This patch replaces the original file existence check so that it now checks if there are any files with the same original filename (no timestamp) in the entire directory structure under the destination path. This avoids unnecessary file copy operations.
@fractaledmind
Copy link
Owner

I know we are taking a while polishing the final exacting details, but we are close and this is a great PR. Thanks for the patience

@imageaid
Copy link
Author

I know we are taking a while polishing the final exacting details, but we are close and this is a great PR. Thanks for the patience

Happy to! I like getting things polished and as close to ideal as possible. No problems at all on my end! I'll commit again later tonight. Time to go walk and feed the pups!

Don't need nested directory in glob
README.md Outdated Show resolved Hide resolved
Copy link
Owner

@fractaledmind fractaledmind left a comment

Choose a reason for hiding this comment

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

Every time I review I find a couple other things, but I can tell that we are very nearly done.

imageaid and others added 5 commits July 19, 2024 11:14
Co-authored-by: Stephen Margheim <stephen.margheim@gmail.com>
Co-authored-by: Stephen Margheim <stephen.margheim@gmail.com>
Co-authored-by: Stephen Margheim <stephen.margheim@gmail.com>
Added instructions to README file for running migration installer after updating the gem. Also, refactored 'solid_errors_tasks.rake' by simplifying the filename generation process during migration. These changes facilitate smoother gem updates and migrations.
@imageaid
Copy link
Author

Ok, Stephen, I think I got that last round of changes in place. Thanks for catching the spelling error(s) 🤦🏻

Let me know how that README line sounds about the post-install message, etc. Or any other changes you find need made. Thanks!

@fractaledmind
Copy link
Owner

I want to chat with @bensheldon some about how he manages versions with schema changes before merging and releasing. I want a clear plan.

@bensheldon
Copy link

👋🏻 Happy to chat. I can try to sketch out a few things (I've been wanting to blog about this forever!) and maybe invite further chatting.

Upfront: GoodJob does a lot of migrations. A lot! I want to say there have been about 30 migration files over its lifespan so far. That's more than like Active Storage which has... 4. So take this with a grain of salt if your gem is more like Active Storage than GoodJob.

  • Required database migrations are breaking changes, so that means if I make a breaking change it warrants a major version release. I try very hard not to allow a database migration to be required.
  • It takes more work to make migrations (or more importantly, their absence) non-breaking and optional. This largely means doing schema checks (does this column exist? if so, then do x, if not, then don't), and writing fairly defensive code (e.g. constructing attribute hashes and array accessors for Active Record models instead of using accessor methods)
  • I make sure that the migrations themselves are idempotent
    • The first time developer rails g good_job:install command installs a single migration that should get the developer the most up-to-date schema.
    • The rails g good_job:update which installs all the update migrations (which could be several) for the current major version. This one gets a little weird because some of the migrations must be noops if they did the former first-time good_job::install migration. So I add a schema check to make them noops. The Rails generator command will detect duplicate migrations based on the name, so it is idempotent.
  • When I do release a major version, I squash down all of the "update" migrations. I do this because I would not be happy, as a first-time user of GoodJob, to immediately be confronted with 30 migrations. The downside of this is that people will upgrade to a major version without applying all the previous major version's migrations and then ask why GoodJob is broken (this is why I do x.99 releases to try to be explicit about the upgrade path). I get many support issues on this when I cut a major release.
  • I have a whole set of generator tests that create a new Rails app and validate that the install and upgrade migrations are in sync. It's very slow but has saved my bacon a lot.

Sorry, that's a wall of text 😅

end
end
end
end

Choose a reason for hiding this comment

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

fyi, Rails Engines have this functionality built in. I don't use it in GoodJob, but that was more out of ignorance at the time than anything else.

https://guides.rubyonrails.org/engines.html#engine-setup

Solid Queue does it really well:

https://github.com/rails/solid_queue/blob/ac477d7b45f530026f36456ee114f223d86fd4ef/lib/generators/solid_queue/install/install_generator.rb

Copy link
Author

Choose a reason for hiding this comment

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

This is really great! Thanks so much @bensheldon (particularly for the great write-up above!)

@imageaid
Copy link
Author

I pushed a small update (well, two) yesterday evening. These two ensure that, in the current approach to the migration, it does copy over correctly.

Note: I did bump the version on this branch (0.4.3.003) so I could ensure that my bundle update grabbed the newest code. That can, of course, be reverted any time.

Let me know, please, if you have any thoughts or approaches you'd like for this PR's final push. Thanks!

@fractaledmind
Copy link
Owner

I'm on vacation for the week. Will wrap up when I get back. Thanks for the great work.

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.

3 participants