feat(runtime): replace tokio+reqwest with asupersync async runtime

- Add HTTP adapter layer (src/http.rs) wrapping asupersync h1 client
- Migrate gitlab client, graphql, and ollama to HTTP adapter
- Swap entrypoint from #[tokio::main] to RuntimeBuilder::new().block_on()
- Rewrite signal handler for asupersync (RuntimeHandle::spawn + ctrl_c())
- Migrate rate limiter sleeps to asupersync::time::sleep(wall_now(), d)
- Add asupersync-native HTTP integration tests
- Convert timeline_seed_tests to RuntimeBuilder pattern

Phases 1-3 of asupersync migration (atomic: code won't compile without all pieces).
This commit is contained in:
teernisse
2026-03-06 15:23:55 -05:00
parent bf977eca1a
commit e8d6c5b15f
16 changed files with 1974 additions and 1189 deletions

View File

@@ -385,25 +385,11 @@ async fn check_ollama(config: Option<&Config>) -> OllamaCheck {
let base_url = &config.embedding.base_url;
let model = &config.embedding.model;
let client = match reqwest::Client::builder()
.timeout(std::time::Duration::from_secs(2))
.build()
{
Ok(client) => client,
Err(e) => {
return OllamaCheck {
result: CheckResult {
status: CheckStatus::Warning,
message: Some(format!("Failed to build HTTP client: {e}")),
},
url: Some(base_url.clone()),
model: Some(model.clone()),
};
}
};
let client = crate::http::Client::with_timeout(std::time::Duration::from_secs(2));
let url = format!("{base_url}/api/tags");
match client.get(format!("{base_url}/api/tags")).send().await {
Ok(response) if response.status().is_success() => {
match client.get(&url, &[]).await {
Ok(response) if response.is_success() => {
#[derive(serde::Deserialize)]
struct TagsResponse {
models: Option<Vec<ModelInfo>>,
@@ -413,7 +399,7 @@ async fn check_ollama(config: Option<&Config>) -> OllamaCheck {
name: String,
}
match response.json::<TagsResponse>().await {
match response.json::<TagsResponse>() {
Ok(data) => {
let models = data.models.unwrap_or_default();
let model_names: Vec<&str> = models
@@ -462,7 +448,7 @@ async fn check_ollama(config: Option<&Config>) -> OllamaCheck {
Ok(response) => OllamaCheck {
result: CheckResult {
status: CheckStatus::Warning,
message: Some(format!("Ollama responded with {}", response.status())),
message: Some(format!("Ollama responded with {}", response.status)),
},
url: Some(base_url.clone()),
model: Some(model.clone()),

View File

@@ -271,11 +271,11 @@ async fn run_ingest_inner(
let token = config.gitlab.resolve_token()?;
let client = GitLabClient::new(
let client = Arc::new(GitLabClient::new(
&config.gitlab.base_url,
&token,
Some(config.sync.requests_per_second),
);
));
let projects = get_projects_to_sync(&conn, &config.projects, project_filter)?;
@@ -352,7 +352,7 @@ async fn run_ingest_inner(
let project_results: Vec<Result<ProjectIngestOutcome>> = stream::iter(projects.iter())
.map(|(local_project_id, gitlab_project_id, path)| {
let client = client.clone();
let client = Arc::clone(&client);
let db_path = db_path.clone();
let config = config.clone();
let resource_type = resource_type_owned.clone();