-
Notifications
You must be signed in to change notification settings - Fork 2
Say why a save or delete was refused, instead of 500 #306
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
Changes from all commits
e36769a
ae181d2
3f25898
3402eb0
fdcaae5
063a88a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,6 +2,7 @@ | |
| using System.Threading.Tasks; | ||
| using Microsoft.EntityFrameworkCore; | ||
| using SW.Bitween.Domain.DataSources; | ||
| using SW.Bitween.Domain; | ||
| using SW.Bitween.Domain.Gateway; | ||
| using SW.EfCoreExtensions; | ||
| using SW.PrimitiveTypes; | ||
|
|
@@ -28,6 +29,21 @@ public async Task<object> Handle(int key) | |
| string.Join(", ", gateways) + | ||
| ". Point them at the internal bus, or delete them, first."); | ||
|
|
||
| // Subscription.DataSourceId restricts too, and was the one left to the database — the | ||
| // commoner case of the two, since a data source is normally read by an integration long | ||
| // before any gateway feeds off it. | ||
| var subscriptions = await dbContext.Set<Subscription>() | ||
| .Where(subscription => subscription.DataSourceId == key) | ||
| .Select(subscription => subscription.Name) | ||
| .Take(5) | ||
| .ToListAsync(); | ||
|
Comment on lines
+35
to
+39
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift Map concurrent foreign-key conflicts at the delete boundary. Each preflight query runs before the delete operation. A concurrent request can insert a referencing row after the query. The configured restrictive foreign keys can then reject the delete with an unhandled Map the relevant conflict to the existing readable validation response:
The 🤖 Prompt for AI Agents |
||
|
|
||
| if (subscriptions.Count > 0) | ||
| throw new SWException( | ||
| "Cannot delete a data source that integrations still read: " + | ||
| string.Join(", ", subscriptions) + | ||
| ". Point them at another data source, or delete them, first."); | ||
|
|
||
| // Dedupe keys cascade with the data source, which is what makes deleting and recreating a | ||
| // data source a genuine reset rather than one that silently suppresses the first messages. | ||
| await dbContext.DeleteByKeyAsync<DataSource>(key); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift
Handle unique-index conflicts at the save boundary.
SubscriptionCategory.CodeandApiGateway.UrlNamehave database unique indexes. Their create and update handlers run a duplicate query beforeSaveChangesAsync, so concurrent requests can both pass the query and race at the database.BitweenDbContext.SaveChangesAsyncdoes not translate the resultingDbUpdateException, and no repository-owned mapper handles these exact conflicts.Map the matching unique-index conflicts to
CATEGORY_CODE_TAKENandGATEWAY_URL_NAME_TAKENat the save boundary. Retain the pre-checks for the usual case.🤖 Prompt for AI Agents