fix: remove deleted workdirs from registry
This commit is contained in:
@@ -9261,9 +9261,8 @@ fn cleanup_working_directory_for_runtime(
|
|||||||
result.diagnostics,
|
result.diagnostics,
|
||||||
));
|
));
|
||||||
};
|
};
|
||||||
let record = workdir_record_from_summary(&api, runtime_id, &working_directory.summary);
|
|
||||||
api.store.upsert_workdir_registry(&record)?;
|
|
||||||
let mut summary = working_directory.summary;
|
let mut summary = working_directory.summary;
|
||||||
|
persist_workdir_cleanup_observation(&api, runtime_id, &summary)?;
|
||||||
apply_workdir_occupancy_projection(&api, &mut summary)?;
|
apply_workdir_occupancy_projection(&api, &mut summary)?;
|
||||||
Ok(Json(BrowserWorkingDirectoryDetailResponse {
|
Ok(Json(BrowserWorkingDirectoryDetailResponse {
|
||||||
workspace_id: api.config.workspace_id.clone(),
|
workspace_id: api.config.workspace_id.clone(),
|
||||||
@@ -14154,11 +14153,7 @@ fn sync_runtime_workdir_observations(
|
|||||||
api.store.upsert_workdir_registry(&updated)?;
|
api.store.upsert_workdir_registry(&updated)?;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
record.materialization_status =
|
persist_workdir_runtime_miss(api, record, result.diagnostics.as_slice())?;
|
||||||
workdir_status_from_runtime_miss(result.diagnostics.as_slice()).to_string();
|
|
||||||
record.cleanliness = "unknown".to_string();
|
|
||||||
record.updated_at = now_registry_timestamp();
|
|
||||||
api.store.upsert_workdir_registry(&record)?;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
@@ -14172,17 +14167,54 @@ fn sync_runtime_workdir_observations(
|
|||||||
Ok(response.diagnostics)
|
Ok(response.diagnostics)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn workdir_status_from_runtime_miss(diagnostics: &[RuntimeDiagnostic]) -> &'static str {
|
fn persist_workdir_cleanup_observation(
|
||||||
if diagnostics
|
api: &WorkspaceApi,
|
||||||
|
runtime_id: &str,
|
||||||
|
summary: &WorkingDirectorySummary,
|
||||||
|
) -> ApiResult<()> {
|
||||||
|
if summary.status == WorkingDirectoryStatusKind::NotFound {
|
||||||
|
api.store.delete_workdir_registry(
|
||||||
|
&api.config.workspace_id,
|
||||||
|
summary.working_directory_id.as_str(),
|
||||||
|
)?;
|
||||||
|
} else {
|
||||||
|
let record = workdir_record_from_summary(api, runtime_id, summary);
|
||||||
|
api.store.upsert_workdir_registry(&record)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn workdir_runtime_miss_is_not_found(diagnostics: &[RuntimeDiagnostic]) -> bool {
|
||||||
|
diagnostics
|
||||||
.iter()
|
.iter()
|
||||||
.any(|diagnostic| diagnostic.code == "working_directory_not_found")
|
.any(|diagnostic| diagnostic.code == "working_directory_not_found")
|
||||||
{
|
}
|
||||||
|
|
||||||
|
fn workdir_status_from_runtime_miss(diagnostics: &[RuntimeDiagnostic]) -> &'static str {
|
||||||
|
if workdir_runtime_miss_is_not_found(diagnostics) {
|
||||||
"not_found"
|
"not_found"
|
||||||
} else {
|
} else {
|
||||||
"unknown"
|
"unknown"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn persist_workdir_runtime_miss(
|
||||||
|
api: &WorkspaceApi,
|
||||||
|
mut record: WorkdirRegistryRecord,
|
||||||
|
diagnostics: &[RuntimeDiagnostic],
|
||||||
|
) -> ApiResult<()> {
|
||||||
|
if workdir_runtime_miss_is_not_found(diagnostics) {
|
||||||
|
api.store
|
||||||
|
.delete_workdir_registry(&api.config.workspace_id, record.workdir_id.as_str())?;
|
||||||
|
} else {
|
||||||
|
record.materialization_status = "unknown".to_string();
|
||||||
|
record.cleanliness = "unknown".to_string();
|
||||||
|
record.updated_at = now_registry_timestamp();
|
||||||
|
api.store.upsert_workdir_registry(&record)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn sync_all_runtime_workdir_observations(api: &WorkspaceApi) -> Vec<RuntimeDiagnostic> {
|
fn sync_all_runtime_workdir_observations(api: &WorkspaceApi) -> Vec<RuntimeDiagnostic> {
|
||||||
let mut diagnostics = Vec::new();
|
let mut diagnostics = Vec::new();
|
||||||
let runtimes = api.runtime.list_runtimes(api.config.max_records.min(200));
|
let runtimes = api.runtime.list_runtimes(api.config.max_records.min(200));
|
||||||
@@ -16980,22 +17012,24 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn workdir_runtime_miss_uses_exact_typed_code() {
|
fn workdir_runtime_miss_uses_exact_typed_code() {
|
||||||
assert_eq!(
|
let typed_not_found = [RuntimeDiagnostic {
|
||||||
workdir_status_from_runtime_miss(&[RuntimeDiagnostic {
|
|
||||||
code: "working_directory_not_found".to_string(),
|
code: "working_directory_not_found".to_string(),
|
||||||
severity: DiagnosticSeverity::Warning,
|
severity: DiagnosticSeverity::Warning,
|
||||||
message: "missing".to_string(),
|
message: "missing".to_string(),
|
||||||
}]),
|
}];
|
||||||
|
assert_eq!(
|
||||||
|
workdir_status_from_runtime_miss(&typed_not_found),
|
||||||
"not_found"
|
"not_found"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert!(workdir_runtime_miss_is_not_found(&typed_not_found));
|
||||||
workdir_status_from_runtime_miss(&[RuntimeDiagnostic {
|
|
||||||
|
let unrelated = [RuntimeDiagnostic {
|
||||||
code: "some_other_not_found".to_string(),
|
code: "some_other_not_found".to_string(),
|
||||||
severity: DiagnosticSeverity::Warning,
|
severity: DiagnosticSeverity::Warning,
|
||||||
message: "not a typed workdir miss".to_string(),
|
message: "not a typed workdir miss".to_string(),
|
||||||
}]),
|
}];
|
||||||
"unknown"
|
assert_eq!(workdir_status_from_runtime_miss(&unrelated), "unknown");
|
||||||
);
|
assert!(!workdir_runtime_miss_is_not_found(&unrelated));
|
||||||
}
|
}
|
||||||
|
|
||||||
struct DeterministicExecutionBackend {
|
struct DeterministicExecutionBackend {
|
||||||
@@ -21308,6 +21342,87 @@ mod tests {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn confirmed_runtime_miss_removes_registry_record_but_unknown_is_retained() {
|
||||||
|
let workspace = tempfile::tempdir().unwrap();
|
||||||
|
init_clean_git_workspace(workspace.path());
|
||||||
|
let api = test_api(workspace.path()).await;
|
||||||
|
seed_cleanup_workdir(&api, "deleted-workdir", "present", "clean");
|
||||||
|
let deleted = api
|
||||||
|
.store
|
||||||
|
.get_workdir_registry(TEST_WORKSPACE_ID, "deleted-workdir")
|
||||||
|
.unwrap()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
persist_workdir_runtime_miss(
|
||||||
|
&api,
|
||||||
|
deleted,
|
||||||
|
&[RuntimeDiagnostic {
|
||||||
|
code: "working_directory_not_found".to_string(),
|
||||||
|
severity: DiagnosticSeverity::Warning,
|
||||||
|
message: "missing".to_string(),
|
||||||
|
}],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
api.store
|
||||||
|
.get_workdir_registry(TEST_WORKSPACE_ID, "deleted-workdir")
|
||||||
|
.unwrap()
|
||||||
|
.is_none()
|
||||||
|
);
|
||||||
|
|
||||||
|
seed_cleanup_workdir(&api, "unknown-workdir", "present", "clean");
|
||||||
|
let unknown = api
|
||||||
|
.store
|
||||||
|
.get_workdir_registry(TEST_WORKSPACE_ID, "unknown-workdir")
|
||||||
|
.unwrap()
|
||||||
|
.unwrap();
|
||||||
|
persist_workdir_runtime_miss(
|
||||||
|
&api,
|
||||||
|
unknown,
|
||||||
|
&[RuntimeDiagnostic {
|
||||||
|
code: "runtime_unavailable".to_string(),
|
||||||
|
severity: DiagnosticSeverity::Warning,
|
||||||
|
message: "temporarily unavailable".to_string(),
|
||||||
|
}],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
api.store
|
||||||
|
.get_workdir_registry(TEST_WORKSPACE_ID, "unknown-workdir")
|
||||||
|
.unwrap()
|
||||||
|
.unwrap()
|
||||||
|
.materialization_status,
|
||||||
|
"unknown"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn cleanup_not_found_observation_removes_registry_record() {
|
||||||
|
let workspace = tempfile::tempdir().unwrap();
|
||||||
|
init_clean_git_workspace(workspace.path());
|
||||||
|
let api = test_api(workspace.path()).await;
|
||||||
|
let working_directory_id = "cleanup-existing";
|
||||||
|
seed_cleanup_workdir(&api, working_directory_id, "present", "clean");
|
||||||
|
let record = api
|
||||||
|
.store
|
||||||
|
.get_workdir_registry(TEST_WORKSPACE_ID, working_directory_id)
|
||||||
|
.unwrap()
|
||||||
|
.unwrap();
|
||||||
|
let mut summary = workdir_summary_from_record(&record);
|
||||||
|
summary.status = WorkingDirectoryStatusKind::NotFound;
|
||||||
|
|
||||||
|
persist_workdir_cleanup_observation(&api, "runtime-test", &summary).unwrap();
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
api.store
|
||||||
|
.get_workdir_registry(TEST_WORKSPACE_ID, working_directory_id)
|
||||||
|
.unwrap()
|
||||||
|
.is_none()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
fn seed_cleanup_link(api: &WorkspaceApi, runtime_worker_id: &str, workdir_id: &str) {
|
fn seed_cleanup_link(api: &WorkspaceApi, runtime_worker_id: &str, workdir_id: &str) {
|
||||||
let runtime_worker_id = runtime_worker_id.parse::<u64>().unwrap();
|
let runtime_worker_id = runtime_worker_id.parse::<u64>().unwrap();
|
||||||
api.store
|
api.store
|
||||||
|
|||||||
Reference in New Issue
Block a user