DeleteJob removes a quantization job and its associated data from disk.
(userID, jobID string)
| 316 | |
| 317 | // DeleteJob removes a quantization job and its associated data from disk. |
| 318 | func (s *QuantizationService) DeleteJob(userID, jobID string) error { |
| 319 | s.mu.Lock() |
| 320 | job, ok := s.jobs.Get(jobID) |
| 321 | if !ok { |
| 322 | s.mu.Unlock() |
| 323 | return fmt.Errorf("job not found: %s", jobID) |
| 324 | } |
| 325 | if userID != "" && job.UserID != userID { |
| 326 | s.mu.Unlock() |
| 327 | return fmt.Errorf("job not found: %s", jobID) |
| 328 | } |
| 329 | |
| 330 | // Reject deletion of actively running jobs |
| 331 | activeStatuses := map[string]bool{ |
| 332 | "queued": true, "downloading": true, "converting": true, "quantizing": true, |
| 333 | } |
| 334 | if activeStatuses[job.Status] { |
| 335 | s.mu.Unlock() |
| 336 | return fmt.Errorf("cannot delete job %s: currently %s (stop it first)", jobID, job.Status) |
| 337 | } |
| 338 | if job.ImportStatus == "importing" { |
| 339 | s.mu.Unlock() |
| 340 | return fmt.Errorf("cannot delete job %s: import in progress", jobID) |
| 341 | } |
| 342 | |
| 343 | importModelName := job.ImportModelName |
| 344 | // Delete write-through removes the DB row (distributed) and broadcasts the |
| 345 | // removal to peer replicas. DeleteJob has no ctx, so use Background. |
| 346 | if err := s.jobs.Delete(context.Background(), jobID); err != nil { |
| 347 | xlog.Warn("Failed to delete job from store", "job_id", jobID, "error", err) |
| 348 | } |
| 349 | s.mu.Unlock() |
| 350 | |
| 351 | // Remove job directory (state.json, output files) |
| 352 | jobDir := s.jobDir(jobID) |
| 353 | if err := os.RemoveAll(jobDir); err != nil { |
| 354 | xlog.Warn("Failed to remove quantization job directory", "job_id", jobID, "path", jobDir, "error", err) |
| 355 | } |
| 356 | |
| 357 | // If an imported model exists, clean it up too |
| 358 | if importModelName != "" { |
| 359 | modelsPath := s.appConfig.SystemState.Model.ModelsPath |
| 360 | modelDir := filepath.Join(modelsPath, importModelName) |
| 361 | configPath := filepath.Join(modelsPath, importModelName+".yaml") |
| 362 | |
| 363 | if err := os.RemoveAll(modelDir); err != nil { |
| 364 | xlog.Warn("Failed to remove imported model directory", "path", modelDir, "error", err) |
| 365 | } |
| 366 | if err := os.Remove(configPath); err != nil && !os.IsNotExist(err) { |
| 367 | xlog.Warn("Failed to remove imported model config", "path", configPath, "error", err) |
| 368 | } |
| 369 | |
| 370 | // Reload model configs |
| 371 | if err := s.configLoader.LoadModelConfigsFromPath(modelsPath, s.appConfig.ToConfigLoaderOptions()...); err != nil { |
| 372 | xlog.Warn("Failed to reload configs after delete", "error", err) |
| 373 | } |
| 374 | } |
| 375 |
nothing calls this directly
no test coverage detected