-
Notifications
You must be signed in to change notification settings - Fork 162
Change error handling for creating parent jobs #2313
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
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 |
|---|---|---|
| @@ -1,4 +1,6 @@ | ||
| use crate::pool::{Connection, ConnectionManager, ManagedConnection, Transaction}; | ||
| use crate::pool::{ | ||
| Connection, ConnectionManager, JobEnqueueResult, ManagedConnection, Transaction, | ||
| }; | ||
| use crate::selector::CompileTestCase; | ||
| use crate::{ | ||
| ArtifactCollection, ArtifactId, ArtifactIdNumber, Benchmark, BenchmarkJob, | ||
|
|
@@ -1773,18 +1775,19 @@ where | |
| }) | ||
| } | ||
|
|
||
| async fn enqueue_parent_benchmark_job( | ||
| async fn enqueue_benchmark_job( | ||
| &self, | ||
| parent_sha: &str, | ||
| request_tag: &str, | ||
| target: Target, | ||
| backend: CodegenBackend, | ||
| profile: Profile, | ||
| benchmark_set: u32, | ||
| kind: BenchmarkJobKind, | ||
| ) -> (bool, anyhow::Result<u32>) { | ||
| let row_result = self | ||
| ) -> JobEnqueueResult { | ||
| // This will return zero rows if the job already exists | ||
| let result = self | ||
| .conn() | ||
| .query_one( | ||
| .query( | ||
| r#" | ||
| INSERT INTO job_queue( | ||
| request_tag, | ||
|
|
@@ -1800,7 +1803,7 @@ where | |
| RETURNING job_queue.id | ||
| "#, | ||
| &[ | ||
| &parent_sha, | ||
| &request_tag, | ||
| &target, | ||
| &backend, | ||
| &profile, | ||
|
|
@@ -1811,75 +1814,28 @@ where | |
| ) | ||
| .await; | ||
|
|
||
| match row_result { | ||
| Ok(row) => (false, Ok(row.get::<_, i32>(0) as u32)), | ||
| match result { | ||
|
Contributor
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. We don't want to be able to duplicate jobs in the database. I think we agree on this. If we inserted a duplicate, somehow, it would trigger a Essentially I think we should leave the two functions distinct. Tempting as it is to refactor it, it makes it more confusing as to what is happening. For reference these are the clauses constraints; CONSTRAINT job_queue_request_fk
FOREIGN KEY (request_tag)
REFERENCES benchmark_request(tag)
ON DELETE CASCADE,
CONSTRAINT job_queue_collector
FOREIGN KEY (collector_id)
REFERENCES collector_config(id)
ON DELETE CASCADE,
CONSTRAINT job_queue_unique
UNIQUE (
request_tag,
target,
backend,
profile,
benchmark_set
)Which we do want. I'm not sure how It doesn't seem clear anymore that we are ignoring parents who already had a job associated with them.
Member
Author
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. Foreign key violation won't be raised because of duplicates, because the query uses
The function now has an explicit result type that encodes this much more clearly than before (where it returned a bool and a result). The commit vs parent job insertion mode is handled in the job queue; we could also put it into this function, but I don't think it's better.
In theory we could also get another FK violation (at this point I think only the collector name), but right now
Contributor
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. Yes the Tracing the logic - we would now fall through to This feels a lot more complicated than what was there previously, it wasn't slick or terribly clever but it was dead simple to follow. I'm not sure there is a compelling enough reason to fragment the logic and generalise for consolidating one function? It feels the fix was changing
Member
Author
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. To me it's easier to follow now - there is a single function that explicitly enumerates which error conditions can happen, and the job queue then explicitly handles these error conditions. As a plus we don't need to have two functions that we need to keep in sync.
Contributor
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. I'm not sure I agree. Having modes passed to a function, following a web of control flow and fall through logic, which could potentially grow, to figure out what is going on vs having two distinct code paths seems more complicated. If we want to centralise things the query could be a good candidate. We could have one function that does the insert and two wrappers called what they are currently? That way we have one central location that avoids drift but two distinct functions that can handle things differently? |
||
| Ok(rows) => { | ||
| let Some(row) = rows.into_iter().next() else { | ||
| return JobEnqueueResult::JobAlreadyExisted; | ||
| }; | ||
| JobEnqueueResult::JobCreated(row.get::<_, i32>(0) as u32) | ||
| } | ||
| Err(e) => { | ||
| if let Some(db_err) = e.as_db_error() { | ||
| if db_err.code() == &SqlState::FOREIGN_KEY_VIOLATION { | ||
| let constraint = db_err.constraint().unwrap_or("benchmark_tag constraint"); | ||
| let detail = db_err.detail().unwrap_or(""); | ||
| return ( | ||
| true, | ||
| Err(anyhow::anyhow!( | ||
| "Foreign key violation on {} for request_tag='{}'. {}", | ||
| constraint, | ||
| parent_sha, | ||
| detail | ||
| )), | ||
| ); | ||
| return JobEnqueueResult::RequestShaNotFound { | ||
| error: format!("Foreign key violation on `{constraint}`: {detail}"), | ||
| }; | ||
| } | ||
| } | ||
| (false, Err(e.into())) | ||
| JobEnqueueResult::Other(e.into()) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| async fn enqueue_benchmark_job( | ||
| &self, | ||
| request_tag: &str, | ||
| target: Target, | ||
| backend: CodegenBackend, | ||
| profile: Profile, | ||
| benchmark_set: u32, | ||
| kind: BenchmarkJobKind, | ||
| ) -> anyhow::Result<Option<u32>> { | ||
| // This will return zero rows if the job already exists | ||
| let rows = self | ||
| .conn() | ||
| .query( | ||
| r#" | ||
| INSERT INTO job_queue( | ||
| request_tag, | ||
| target, | ||
| backend, | ||
| profile, | ||
| benchmark_set, | ||
| status, | ||
| kind | ||
| ) | ||
| VALUES ($1, $2, $3, $4, $5, $6, $7) | ||
| ON CONFLICT DO NOTHING | ||
| RETURNING job_queue.id | ||
| "#, | ||
| &[ | ||
| &request_tag, | ||
| &target, | ||
| &backend, | ||
| &profile, | ||
| &(benchmark_set as i32), | ||
| &BENCHMARK_JOB_STATUS_QUEUED_STR, | ||
| &kind, | ||
| ], | ||
| ) | ||
| .await | ||
| .context("failed to insert benchmark_job")?; | ||
| if let Some(row) = rows.first() { | ||
| Ok(Some(row.get::<_, i32>(0) as u32)) | ||
| } else { | ||
| Ok(None) | ||
| } | ||
| } | ||
|
|
||
| async fn get_compile_test_cases_with_measurements( | ||
| &self, | ||
| artifact_row_id: &ArtifactIdNumber, | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.