mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-03 01:40:21 +08:00
refactor: 抽离 AI pipeline 与调度共享能力逻辑
This commit is contained in:
@@ -48,7 +48,7 @@ impl RequestCandidateReadRepository for InMemoryRequestCandidateRepository {
|
||||
left.candidate_index
|
||||
.cmp(&right.candidate_index)
|
||||
.then(left.retry_index.cmp(&right.retry_index))
|
||||
.then(left.created_at_unix_secs.cmp(&right.created_at_unix_secs))
|
||||
.then(left.created_at_unix_ms.cmp(&right.created_at_unix_ms))
|
||||
});
|
||||
Ok(rows)
|
||||
}
|
||||
@@ -68,7 +68,7 @@ impl RequestCandidateReadRepository for InMemoryRequestCandidateRepository {
|
||||
.values()
|
||||
.cloned()
|
||||
.collect::<Vec<_>>();
|
||||
rows.sort_by(|left, right| right.created_at_unix_secs.cmp(&left.created_at_unix_secs));
|
||||
rows.sort_by(|left, right| right.created_at_unix_ms.cmp(&left.created_at_unix_ms));
|
||||
rows.truncate(limit);
|
||||
Ok(rows)
|
||||
}
|
||||
@@ -90,7 +90,7 @@ impl RequestCandidateReadRepository for InMemoryRequestCandidateRepository {
|
||||
.filter(|row| row.provider_id.as_deref() == Some(provider_id))
|
||||
.cloned()
|
||||
.collect::<Vec<_>>();
|
||||
rows.sort_by(|left, right| right.created_at_unix_secs.cmp(&left.created_at_unix_secs));
|
||||
rows.sort_by(|left, right| right.created_at_unix_ms.cmp(&left.created_at_unix_ms));
|
||||
rows.truncate(limit);
|
||||
Ok(rows)
|
||||
}
|
||||
@@ -115,7 +115,7 @@ impl RequestCandidateReadRepository for InMemoryRequestCandidateRepository {
|
||||
row.endpoint_id
|
||||
.as_ref()
|
||||
.is_some_and(|endpoint_id| endpoint_ids.contains(endpoint_id))
|
||||
&& row.created_at_unix_secs >= since_unix_secs
|
||||
&& row.created_at_unix_ms >= since_unix_secs * 1000
|
||||
&& matches!(
|
||||
row.status,
|
||||
RequestCandidateStatus::Success
|
||||
@@ -125,7 +125,7 @@ impl RequestCandidateReadRepository for InMemoryRequestCandidateRepository {
|
||||
})
|
||||
.cloned()
|
||||
.collect::<Vec<_>>();
|
||||
rows.sort_by(|left, right| right.created_at_unix_secs.cmp(&left.created_at_unix_secs));
|
||||
rows.sort_by(|left, right| right.created_at_unix_ms.cmp(&left.created_at_unix_ms));
|
||||
rows.truncate(limit);
|
||||
Ok(rows)
|
||||
}
|
||||
@@ -150,7 +150,9 @@ impl RequestCandidateReadRepository for InMemoryRequestCandidateRepository {
|
||||
let Some(endpoint_id) = row.endpoint_id.as_ref() else {
|
||||
continue;
|
||||
};
|
||||
if !endpoint_ids.contains(endpoint_id) || row.created_at_unix_secs < since_unix_secs {
|
||||
if !endpoint_ids.contains(endpoint_id)
|
||||
|| row.created_at_unix_ms < since_unix_secs * 1000
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if !matches!(
|
||||
@@ -200,7 +202,7 @@ impl RequestCandidateReadRepository for InMemoryRequestCandidateRepository {
|
||||
}
|
||||
|
||||
let endpoint_ids = endpoint_ids.iter().cloned().collect::<BTreeSet<_>>();
|
||||
let span = until_unix_secs.saturating_sub(since_unix_secs);
|
||||
let span_ms = until_unix_secs.saturating_sub(since_unix_secs) * 1000;
|
||||
let mut buckets = BTreeMap::<(String, u32), PublicHealthTimelineBucket>::new();
|
||||
|
||||
for row in self
|
||||
@@ -213,8 +215,8 @@ impl RequestCandidateReadRepository for InMemoryRequestCandidateRepository {
|
||||
continue;
|
||||
};
|
||||
if !endpoint_ids.contains(endpoint_id)
|
||||
|| row.created_at_unix_secs < since_unix_secs
|
||||
|| row.created_at_unix_secs > until_unix_secs
|
||||
|| row.created_at_unix_ms < since_unix_secs * 1000
|
||||
|| row.created_at_unix_ms > until_unix_secs * 1000
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -227,11 +229,13 @@ impl RequestCandidateReadRepository for InMemoryRequestCandidateRepository {
|
||||
continue;
|
||||
}
|
||||
|
||||
let segment_idx = if span == 0 {
|
||||
let segment_idx = if span_ms == 0 {
|
||||
0
|
||||
} else {
|
||||
let offset = row.created_at_unix_secs.saturating_sub(since_unix_secs);
|
||||
let idx = ((offset as u128) * (segments as u128) / (span as u128)) as u32;
|
||||
let offset = row
|
||||
.created_at_unix_ms
|
||||
.saturating_sub(since_unix_secs * 1000);
|
||||
let idx = ((offset as u128) * (segments as u128) / (span_ms as u128)) as u32;
|
||||
idx.min(segments.saturating_sub(1))
|
||||
};
|
||||
let bucket = buckets
|
||||
@@ -242,8 +246,8 @@ impl RequestCandidateReadRepository for InMemoryRequestCandidateRepository {
|
||||
total_count: 0,
|
||||
success_count: 0,
|
||||
failed_count: 0,
|
||||
min_created_at_unix_secs: None,
|
||||
max_created_at_unix_secs: None,
|
||||
min_created_at_unix_ms: None,
|
||||
max_created_at_unix_ms: None,
|
||||
});
|
||||
bucket.total_count += 1;
|
||||
if row.status == RequestCandidateStatus::Success {
|
||||
@@ -251,17 +255,17 @@ impl RequestCandidateReadRepository for InMemoryRequestCandidateRepository {
|
||||
} else if row.status == RequestCandidateStatus::Failed {
|
||||
bucket.failed_count += 1;
|
||||
}
|
||||
bucket.min_created_at_unix_secs = Some(
|
||||
bucket.min_created_at_unix_ms = Some(
|
||||
bucket
|
||||
.min_created_at_unix_secs
|
||||
.map(|value| value.min(row.created_at_unix_secs))
|
||||
.unwrap_or(row.created_at_unix_secs),
|
||||
.min_created_at_unix_ms
|
||||
.map(|value| value.min(row.created_at_unix_ms))
|
||||
.unwrap_or(row.created_at_unix_ms),
|
||||
);
|
||||
bucket.max_created_at_unix_secs = Some(
|
||||
bucket.max_created_at_unix_ms = Some(
|
||||
bucket
|
||||
.max_created_at_unix_secs
|
||||
.map(|value| value.max(row.created_at_unix_secs))
|
||||
.unwrap_or(row.created_at_unix_secs),
|
||||
.max_created_at_unix_ms
|
||||
.map(|value| value.max(row.created_at_unix_ms))
|
||||
.unwrap_or(row.created_at_unix_ms),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -290,12 +294,12 @@ impl RequestCandidateWriteRepository for InMemoryRequestCandidateRepository {
|
||||
})
|
||||
.cloned();
|
||||
|
||||
let created_at_unix_secs = existing
|
||||
let created_at_unix_ms = existing
|
||||
.as_ref()
|
||||
.map(|row| row.created_at_unix_secs)
|
||||
.or(candidate.created_at_unix_secs)
|
||||
.or(candidate.started_at_unix_secs)
|
||||
.or(candidate.finished_at_unix_secs)
|
||||
.map(|row| row.created_at_unix_ms)
|
||||
.or(candidate.created_at_unix_ms)
|
||||
.or(candidate.started_at_unix_ms)
|
||||
.or(candidate.finished_at_unix_ms)
|
||||
.unwrap_or_default();
|
||||
|
||||
let stored = StoredRequestCandidate {
|
||||
@@ -357,13 +361,13 @@ impl RequestCandidateWriteRepository for InMemoryRequestCandidateRepository {
|
||||
.as_ref()
|
||||
.and_then(|row| row.required_capabilities.clone())
|
||||
}),
|
||||
created_at_unix_secs,
|
||||
started_at_unix_secs: candidate
|
||||
.started_at_unix_secs
|
||||
.or_else(|| existing.as_ref().and_then(|row| row.started_at_unix_secs)),
|
||||
finished_at_unix_secs: candidate
|
||||
.finished_at_unix_secs
|
||||
.or_else(|| existing.as_ref().and_then(|row| row.finished_at_unix_secs)),
|
||||
created_at_unix_ms,
|
||||
started_at_unix_ms: candidate
|
||||
.started_at_unix_ms
|
||||
.or_else(|| existing.as_ref().and_then(|row| row.started_at_unix_ms)),
|
||||
finished_at_unix_ms: candidate
|
||||
.finished_at_unix_ms
|
||||
.or_else(|| existing.as_ref().and_then(|row| row.finished_at_unix_ms)),
|
||||
};
|
||||
|
||||
by_id.insert(stored.id.clone(), stored.clone());
|
||||
@@ -385,8 +389,8 @@ impl RequestCandidateWriteRepository for InMemoryRequestCandidateRepository {
|
||||
.expect("request candidate repository lock");
|
||||
let mut ids = by_id
|
||||
.values()
|
||||
.filter(|row| row.created_at_unix_secs < created_before_unix_secs)
|
||||
.map(|row| (row.created_at_unix_secs, row.id.clone()))
|
||||
.filter(|row| row.created_at_unix_ms < created_before_unix_secs * 1000)
|
||||
.map(|row| (row.created_at_unix_ms, row.id.clone()))
|
||||
.collect::<Vec<_>>();
|
||||
ids.sort();
|
||||
|
||||
@@ -411,7 +415,7 @@ mod tests {
|
||||
fn sample_candidate(
|
||||
id: &str,
|
||||
request_id: &str,
|
||||
created_at_unix_secs: i64,
|
||||
created_at_unix_ms: i64,
|
||||
) -> StoredRequestCandidate {
|
||||
StoredRequestCandidate::new(
|
||||
id.to_string(),
|
||||
@@ -435,9 +439,9 @@ mod tests {
|
||||
Some(1),
|
||||
None,
|
||||
None,
|
||||
created_at_unix_secs,
|
||||
Some(created_at_unix_secs),
|
||||
Some(created_at_unix_secs + 1),
|
||||
created_at_unix_ms,
|
||||
Some(created_at_unix_ms),
|
||||
Some(created_at_unix_ms + 1),
|
||||
)
|
||||
.expect("candidate should build")
|
||||
}
|
||||
@@ -480,8 +484,8 @@ mod tests {
|
||||
#[tokio::test]
|
||||
async fn aggregates_finalized_health_data_by_endpoint_ids() {
|
||||
let repository = InMemoryRequestCandidateRepository::seed(vec![
|
||||
sample_candidate("cand-1", "req-1", 100),
|
||||
sample_candidate("cand-2", "req-2", 200),
|
||||
sample_candidate("cand-1", "req-1", 100_000),
|
||||
sample_candidate("cand-2", "req-2", 200_000),
|
||||
]);
|
||||
|
||||
let counts = repository
|
||||
@@ -538,9 +542,9 @@ mod tests {
|
||||
concurrent_requests: None,
|
||||
extra_data: None,
|
||||
required_capabilities: None,
|
||||
created_at_unix_secs: Some(100),
|
||||
started_at_unix_secs: None,
|
||||
finished_at_unix_secs: None,
|
||||
created_at_unix_ms: Some(100),
|
||||
started_at_unix_ms: None,
|
||||
finished_at_unix_ms: None,
|
||||
})
|
||||
.await
|
||||
.expect("create should succeed");
|
||||
@@ -570,9 +574,9 @@ mod tests {
|
||||
concurrent_requests: Some(2),
|
||||
extra_data: None,
|
||||
required_capabilities: None,
|
||||
created_at_unix_secs: None,
|
||||
started_at_unix_secs: Some(101),
|
||||
finished_at_unix_secs: Some(102),
|
||||
created_at_unix_ms: None,
|
||||
started_at_unix_ms: Some(101),
|
||||
finished_at_unix_ms: Some(102),
|
||||
})
|
||||
.await
|
||||
.expect("update should succeed");
|
||||
@@ -580,7 +584,7 @@ mod tests {
|
||||
assert_eq!(updated.status, RequestCandidateStatus::Success);
|
||||
assert_eq!(updated.status_code, Some(200));
|
||||
assert_eq!(updated.latency_ms, Some(25));
|
||||
assert_eq!(updated.started_at_unix_secs, Some(101));
|
||||
assert_eq!(updated.started_at_unix_ms, Some(101));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
||||
@@ -34,9 +34,9 @@ SELECT
|
||||
concurrent_requests,
|
||||
extra_data,
|
||||
required_capabilities,
|
||||
CAST(EXTRACT(EPOCH FROM created_at) AS BIGINT) AS created_at_unix_secs,
|
||||
CAST(EXTRACT(EPOCH FROM started_at) AS BIGINT) AS started_at_unix_secs,
|
||||
CAST(EXTRACT(EPOCH FROM finished_at) AS BIGINT) AS finished_at_unix_secs
|
||||
CAST(EXTRACT(EPOCH FROM created_at) * 1000 AS BIGINT) AS created_at_unix_ms,
|
||||
CAST(EXTRACT(EPOCH FROM started_at) * 1000 AS BIGINT) AS started_at_unix_ms,
|
||||
CAST(EXTRACT(EPOCH FROM finished_at) * 1000 AS BIGINT) AS finished_at_unix_ms
|
||||
FROM request_candidates
|
||||
WHERE request_id = $1
|
||||
ORDER BY candidate_index ASC, retry_index ASC, created_at ASC
|
||||
@@ -65,9 +65,9 @@ SELECT
|
||||
concurrent_requests,
|
||||
extra_data,
|
||||
required_capabilities,
|
||||
CAST(EXTRACT(EPOCH FROM created_at) AS BIGINT) AS created_at_unix_secs,
|
||||
CAST(EXTRACT(EPOCH FROM started_at) AS BIGINT) AS started_at_unix_secs,
|
||||
CAST(EXTRACT(EPOCH FROM finished_at) AS BIGINT) AS finished_at_unix_secs
|
||||
CAST(EXTRACT(EPOCH FROM created_at) * 1000 AS BIGINT) AS created_at_unix_ms,
|
||||
CAST(EXTRACT(EPOCH FROM started_at) * 1000 AS BIGINT) AS started_at_unix_ms,
|
||||
CAST(EXTRACT(EPOCH FROM finished_at) * 1000 AS BIGINT) AS finished_at_unix_ms
|
||||
FROM request_candidates
|
||||
ORDER BY created_at DESC
|
||||
LIMIT $1
|
||||
@@ -96,9 +96,9 @@ SELECT
|
||||
concurrent_requests,
|
||||
extra_data,
|
||||
required_capabilities,
|
||||
CAST(EXTRACT(EPOCH FROM created_at) AS BIGINT) AS created_at_unix_secs,
|
||||
CAST(EXTRACT(EPOCH FROM started_at) AS BIGINT) AS started_at_unix_secs,
|
||||
CAST(EXTRACT(EPOCH FROM finished_at) AS BIGINT) AS finished_at_unix_secs
|
||||
CAST(EXTRACT(EPOCH FROM created_at) * 1000 AS BIGINT) AS created_at_unix_ms,
|
||||
CAST(EXTRACT(EPOCH FROM started_at) * 1000 AS BIGINT) AS started_at_unix_ms,
|
||||
CAST(EXTRACT(EPOCH FROM finished_at) * 1000 AS BIGINT) AS finished_at_unix_ms
|
||||
FROM request_candidates
|
||||
WHERE provider_id = $1
|
||||
ORDER BY created_at DESC
|
||||
@@ -128,9 +128,9 @@ SELECT
|
||||
concurrent_requests,
|
||||
extra_data,
|
||||
required_capabilities,
|
||||
CAST(EXTRACT(EPOCH FROM created_at) AS BIGINT) AS created_at_unix_secs,
|
||||
CAST(EXTRACT(EPOCH FROM started_at) AS BIGINT) AS started_at_unix_secs,
|
||||
CAST(EXTRACT(EPOCH FROM finished_at) AS BIGINT) AS finished_at_unix_secs
|
||||
CAST(EXTRACT(EPOCH FROM created_at) * 1000 AS BIGINT) AS created_at_unix_ms,
|
||||
CAST(EXTRACT(EPOCH FROM started_at) * 1000 AS BIGINT) AS started_at_unix_ms,
|
||||
CAST(EXTRACT(EPOCH FROM finished_at) * 1000 AS BIGINT) AS finished_at_unix_ms
|
||||
FROM request_candidates
|
||||
WHERE endpoint_id = ANY($1)
|
||||
AND created_at >= TO_TIMESTAMP($2)
|
||||
@@ -158,8 +158,8 @@ SELECT
|
||||
COUNT(id) AS total_count,
|
||||
SUM(CASE WHEN status = 'success' THEN 1 ELSE 0 END) AS success_count,
|
||||
SUM(CASE WHEN status = 'failed' THEN 1 ELSE 0 END) AS failed_count,
|
||||
CAST(EXTRACT(EPOCH FROM MIN(created_at)) AS BIGINT) AS min_created_at_unix_secs,
|
||||
CAST(EXTRACT(EPOCH FROM MAX(created_at)) AS BIGINT) AS max_created_at_unix_secs
|
||||
CAST(EXTRACT(EPOCH FROM MIN(created_at)) * 1000 AS BIGINT) AS min_created_at_unix_ms,
|
||||
CAST(EXTRACT(EPOCH FROM MAX(created_at)) * 1000 AS BIGINT) AS max_created_at_unix_ms
|
||||
FROM request_candidates
|
||||
WHERE endpoint_id = ANY($1)
|
||||
AND created_at >= TO_TIMESTAMP($2)
|
||||
@@ -219,9 +219,9 @@ VALUES (
|
||||
$19,
|
||||
$20,
|
||||
$21,
|
||||
TO_TIMESTAMP(COALESCE($22, 0)),
|
||||
TO_TIMESTAMP($23),
|
||||
TO_TIMESTAMP($24)
|
||||
TO_TIMESTAMP(COALESCE($22, 0) / 1000.0),
|
||||
TO_TIMESTAMP($23 / 1000.0),
|
||||
TO_TIMESTAMP($24 / 1000.0)
|
||||
)
|
||||
ON CONFLICT (request_id, candidate_index, retry_index)
|
||||
DO UPDATE SET
|
||||
@@ -266,9 +266,9 @@ RETURNING
|
||||
concurrent_requests,
|
||||
extra_data,
|
||||
required_capabilities,
|
||||
CAST(EXTRACT(EPOCH FROM created_at) AS BIGINT) AS created_at_unix_secs,
|
||||
CAST(EXTRACT(EPOCH FROM started_at) AS BIGINT) AS started_at_unix_secs,
|
||||
CAST(EXTRACT(EPOCH FROM finished_at) AS BIGINT) AS finished_at_unix_secs
|
||||
CAST(EXTRACT(EPOCH FROM created_at) * 1000 AS BIGINT) AS created_at_unix_ms,
|
||||
CAST(EXTRACT(EPOCH FROM started_at) * 1000 AS BIGINT) AS started_at_unix_ms,
|
||||
CAST(EXTRACT(EPOCH FROM finished_at) * 1000 AS BIGINT) AS finished_at_unix_ms
|
||||
"#;
|
||||
|
||||
const DELETE_CREATED_BEFORE_SQL: &str = r#"
|
||||
@@ -481,30 +481,24 @@ impl SqlxRequestCandidateReadRepository {
|
||||
)
|
||||
},
|
||||
)?,
|
||||
min_created_at_unix_secs: row_get::<Option<i64>>(
|
||||
row,
|
||||
"min_created_at_unix_secs",
|
||||
)?
|
||||
.map(|value| {
|
||||
u64::try_from(value).map_err(|_| {
|
||||
DataLayerError::UnexpectedValue(format!(
|
||||
"public health min_created_at_unix_secs out of range: {value}"
|
||||
))
|
||||
min_created_at_unix_ms: row_get::<Option<i64>>(row, "min_created_at_unix_ms")?
|
||||
.map(|value| {
|
||||
u64::try_from(value).map_err(|_| {
|
||||
DataLayerError::UnexpectedValue(format!(
|
||||
"public health min_created_at_unix_ms out of range: {value}"
|
||||
))
|
||||
})
|
||||
})
|
||||
})
|
||||
.transpose()?,
|
||||
max_created_at_unix_secs: row_get::<Option<i64>>(
|
||||
row,
|
||||
"max_created_at_unix_secs",
|
||||
)?
|
||||
.map(|value| {
|
||||
u64::try_from(value).map_err(|_| {
|
||||
DataLayerError::UnexpectedValue(format!(
|
||||
"public health max_created_at_unix_secs out of range: {value}"
|
||||
))
|
||||
.transpose()?,
|
||||
max_created_at_unix_ms: row_get::<Option<i64>>(row, "max_created_at_unix_ms")?
|
||||
.map(|value| {
|
||||
u64::try_from(value).map_err(|_| {
|
||||
DataLayerError::UnexpectedValue(format!(
|
||||
"public health max_created_at_unix_ms out of range: {value}"
|
||||
))
|
||||
})
|
||||
})
|
||||
})
|
||||
.transpose()?,
|
||||
.transpose()?,
|
||||
})
|
||||
})
|
||||
.collect()
|
||||
@@ -544,9 +538,9 @@ impl SqlxRequestCandidateReadRepository {
|
||||
.bind(candidate.concurrent_requests.map(to_i32).transpose()?)
|
||||
.bind(&candidate.extra_data)
|
||||
.bind(&candidate.required_capabilities)
|
||||
.bind(candidate.created_at_unix_secs.map(|value| value as f64))
|
||||
.bind(candidate.started_at_unix_secs.map(|value| value as f64))
|
||||
.bind(candidate.finished_at_unix_secs.map(|value| value as f64))
|
||||
.bind(candidate.created_at_unix_ms.map(|value| value as f64))
|
||||
.bind(candidate.started_at_unix_ms.map(|value| value as f64))
|
||||
.bind(candidate.finished_at_unix_ms.map(|value| value as f64))
|
||||
.fetch_one(&mut **tx)
|
||||
.await
|
||||
.map_postgres_err()?;
|
||||
@@ -683,9 +677,9 @@ fn map_request_candidate_row(
|
||||
row_get(row, "concurrent_requests")?,
|
||||
row_get(row, "extra_data")?,
|
||||
row_get(row, "required_capabilities")?,
|
||||
row_get(row, "created_at_unix_secs")?,
|
||||
row_get(row, "started_at_unix_secs")?,
|
||||
row_get(row, "finished_at_unix_secs")?,
|
||||
row_get(row, "created_at_unix_ms")?,
|
||||
row_get(row, "started_at_unix_ms")?,
|
||||
row_get(row, "finished_at_unix_ms")?,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user