Repository navigation
Conversation
The task held a worker transaction open for the whole run, up to its 120 s deadline, pinning xmin on the default primary. Each PENDING row, state change and file upload now commits on its own, and a comparison whose diff or upload raises is marked FAILED so it can be retried.
Recording each comparison as it finished left PENDING, PROCESSING and FAILED rows behind when a run failed, and neither the sweeper nor a member's compare request recovers those. The run now computes every result first and records them in one short transaction, so a failed run leaves no rows, as it did before.
A deadline landing while the recording transaction commits left SUCCESS rows pointing at deleted files. Cleanup now checks for a referencing row first. The single-comparison path claims its row with a conditional update, so it cannot overwrite a result an overlapping run recorded.
The old task dispatched the status check and PR comment inside its transaction, so a deadline landing on the COMMIT itself never lost them. Dispatching after the recording transaction reopened that window.
The single-comparison helper marked its row PROCESSING and later SUCCESS without checking the row was still PENDING, so two overlapping runs could overwrite each other. It also uploaded the result inside the transaction that records it, and left the file behind when that write failed.
…e/fix/preprod-compare-transaction
…x/preprod-compare-transaction
The timeout sweeper fails PROCESSING comparisons by date_updated, and the claim's .update() skips auto_now, so a stale PENDING row would be swept mid-run if the claim stopped setting it.
|
bot: diagram the transaction scope before and after this change |
|
🌱 Before this change the whole automatic run sat inside one transaction. Now the downloads, diffs and uploads run with no transaction open, and only the row writes share one short transaction at the end. Before, After,
The manual and monitor path, The head has moved to
This message was generated by a bot; every message tagged 🌱 is from it. Reply with |
jamieQ
left a comment
There was a problem hiding this comment.
Changes generally make sense, though personally I find it somewhat harder to reason about now 😅. I guess that's the nature of distributed systems though... Left a number of thoughts for your consideration. Also, as a slight aside, the "success criteria" in the linked ticket doesn't seem like it totally matches the implementation (e.g. pending rows created before side effects & don't roll back completed work).
| ) | ||
|
|
||
| provisional_file_name = f"{head_size_metric.id}-{base_size_metric.id}" | ||
| result_file = _store_size_comparison_results(provisional_file_name, comparison_results) |
There was a problem hiding this comment.
Not sure if it's too much of an edge case to be worth dealing with, but it seems like if the task raised an exception after we create the file but before it's saved in the result_files array in the caller we'd forget to clean it up. Something similar maybe exists for the run_size_analysis_comparison flow too.
There was a problem hiding this comment.
Definitely an edge case and you're right run_size_analysis_comparison has that gap. Adding a sweep job that deletes orphaned comparison files is the proper way to do it IMO. I think it's fine to ship for now, the loss is just tiny data growth for now.
A failing delete in the upload's except block replaced the original error. Cleanup now goes through the helper that logs and swallows its own failures. Also gives the lost-race skip its own log event, makes the prepared-comparison type private, and covers a deadline that lands inside the recording transaction.
…x/preprod-compare-transaction
resolves INFRENG-977
Runs the preprod size comparison task without holding a database transaction across the file downloads, the diff and the result uploads.
The task used to wrap the whole run in one transaction, open for up to its 120 s deadline, with a savepoint per write inside it. It now computes and uploads every result first and records the rows in one short transaction at the end, so a run is still all-or-nothing: a failure or a deadline leaves no rows, as before. Worth weighing in review: two runs that overlap on the same pair now both compute the diff where the second used to block on the first's transaction, and the one that loses deletes its own result file. The manual and monitor paths claim their row with a conditional update for the same reason.