Refactor listing VMs (#399)

* Removed unnesesary ListOptions

* Refactor genericList to accept string prefixes instead of byte slices

* Optimize VM listing logic with singleflight to deduplicate concurrent request

* Refactor VM listing logic: rename variables for clarity and update error messages

* fix: address PR review feedback

- use singleflight DoChan with context cancellation for list VMs

🤖 Generated with [Codex](https://chatgpt.com/codex)

Co-Authored-By: Codex <codex@openai.com>

---------

Co-authored-by: Codex <codex@openai.com>
This commit is contained in:
Fedor Korotkov
2026-02-05 18:51:45 +01:00
committed by GitHub
co-authored by Codex
parent 230a83c740
commit be869f10d4
8 changed files with 55 additions and 56 deletions
+44 -16
View File
@@ -299,11 +299,9 @@ func (controller *Controller) listVMs(ctx *gin.Context) responder.Responder {
return responder
}
var opts []storepkg.ListOption
var filters []v1.Filter
if filterRaw := ctx.Query("filter"); filterRaw != "" {
var filters []v1.Filter
for _, filterRaw := range strings.Split(filterRaw, ",") {
filter, err := v1.NewFilter(filterRaw)
if err != nil {
@@ -312,23 +310,53 @@ func (controller *Controller) listVMs(ctx *gin.Context) responder.Responder {
filters = append(filters, filter)
}
if len(filters) > 1 {
return responder.JSON(http.StatusPreconditionFailed, NewErrorResponse("only "+
"a single filter is currently supported"))
}
opts = append(opts, storepkg.WithListFilters(filters...))
}
return controller.storeView(func(txn storepkg.Transaction) responder.Responder {
vms, err := txn.ListVMs(opts...)
if err != nil {
return responder.Error(err)
}
resultCh := controller.single.DoChan("list-vms", func() (interface{}, error) {
var vms []v1.VM
return responder.JSON(http.StatusOK, vms)
viewErr := controller.store.View(func(txn storepkg.Transaction) (err error) {
vms, err = txn.ListVMs()
return
})
return vms, viewErr
})
var computedVMs interface{}
var err error
select {
case <-ctx.Done():
return responder.Empty()
case result := <-resultCh:
computedVMs = result.Val
err = result.Err
}
if err != nil {
return responder.Error(err)
}
allVMs, ok := computedVMs.([]v1.VM)
if !ok {
controller.logger.Errorf("failed to compute vms: %T", computedVMs)
return responder.Code(http.StatusInternalServerError)
}
vms := make([]v1.VM, 0, len(allVMs))
Outer:
for _, vm := range allVMs {
for _, filter := range filters {
if !vm.Match(filter) {
continue Outer
}
}
vms = append(vms, vm)
}
return responder.JSON(http.StatusOK, vms)
}
func (controller *Controller) deleteVM(ctx *gin.Context) responder.Responder {