Skip to content

Commit 3989d3e

Browse files
authored
✨ Support bulk task cancel using filter criteria. (#774)
Update the bulk (cancel) action route to be an action against the collection. Also, instead of passing a list of IDs in the body, use a filter instead. This is more flexible and RESTful. Example: /tasks/cancel?filter=id:(1|2|3) /tasks/cancel?filter=application.id:44 /tasks/cancel?filter=kind:analysis,state=Pending The only downside is the url length may be an issue for many thousands of cancels (by id). However, I don't see that as a mainstream use-case. I would think that use-case would be better supported by filtering by other than id. To cancel all running tasks, an empty filter may be passed. --------- Signed-off-by: Jeff Ortel <[email protected]>
1 parent 55d5e94 commit 3989d3e

File tree

3 files changed

+71
-36
lines changed

3 files changed

+71
-36
lines changed

api/task.go

+56-32
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,15 @@ const (
2525
TasksReportRoot = TasksRoot + "/report"
2626
TasksReportQueueRoot = TasksReportRoot + "/queue"
2727
TasksReportDashboardRoot = TasksReportRoot + "/dashboard"
28+
TasksCancelRoot = TasksRoot + "/cancel"
2829
TaskRoot = TasksRoot + "/:" + ID
2930
TaskReportRoot = TaskRoot + "/report"
3031
TaskAttachedRoot = TaskRoot + "/attached"
3132
TaskBucketRoot = TaskRoot + "/bucket"
3233
TaskBucketContentRoot = TaskBucketRoot + "/*" + Wildcard
3334
TaskSubmitRoot = TaskRoot + "/submit"
3435
TaskCancelRoot = TaskRoot + "/cancel"
35-
TaskCancelListRoot = TasksRoot + "/cancel/list"
3636
)
37-
3837
const (
3938
Submit = "submit"
4039
)
@@ -60,7 +59,7 @@ func (h TaskHandler) AddRoutes(e *gin.Engine) {
6059
// Actions
6160
routeGroup.PUT(TaskSubmitRoot, Transaction, h.Submit)
6261
routeGroup.PUT(TaskCancelRoot, h.Cancel)
63-
routeGroup.PUT(TaskCancelListRoot, h.CancelList)
62+
routeGroup.PUT(TasksCancelRoot, h.BulkCancel)
6463
// Bucket
6564
routeGroup = e.Group("/")
6665
routeGroup.Use(Required("tasks.bucket"))
@@ -470,13 +469,13 @@ func (h TaskHandler) Submit(ctx *gin.Context) {
470469
h.Update(ctx)
471470
}
472471

473-
// // Cancel godoc
474-
// // @summary Cancel a task.
475-
// // @description Cancel a task.
476-
// // @tags tasks
477-
// // @success 202
478-
// // @router /tasks/{id}/cancel [put]
479-
// // @param id path int true "Task ID"
472+
// Cancel godoc
473+
// @summary Cancel a task.
474+
// @description Cancel a task.
475+
// @tags tasks
476+
// @success 202
477+
// @router /tasks/{id}/cancel [put]
478+
// @param id path int true "Task ID"
480479
func (h TaskHandler) Cancel(ctx *gin.Context) {
481480
id := h.pk(ctx)
482481
rtx := RichContext(ctx)
@@ -489,35 +488,60 @@ func (h TaskHandler) Cancel(ctx *gin.Context) {
489488
h.Status(ctx, http.StatusAccepted)
490489
}
491490

492-
// CancelList godoc
493-
// @summary Cancel multiple tasks.
494-
// @description Cancel multiple tasks by IDs.
491+
// BulkCancel godoc
492+
// @summary Cancel tasks matched by the filter.
493+
// @description Cancel tasks matched by the filter.
494+
// @description Caution: an empty filter matches all tasks.
495+
// @description Filters:
496+
// @description - id
497+
// @description - name
498+
// @description - locator
499+
// @description - kind
500+
// @description - addon
501+
// @description - state
502+
// @description - application.id
495503
// @tags tasks
496504
// @success 202
497505
// @router /tasks/cancel/list [put]
498506
// @param tasks body []uint true "List of Task IDs"
499-
func (h TaskHandler) CancelList(ctx *gin.Context) {
500-
ids := []uint{}
501-
502-
if err := h.Bind(ctx, &ids); err != nil {
503-
_ = ctx.Error(err)
504-
return
505-
}
506-
507-
rtx := RichContext(ctx)
508-
509-
for _, id := range ids {
510-
err := rtx.TaskManager.Cancel(h.DB(ctx), id)
511-
if err != nil {
512-
_ = ctx.Error(err)
513-
return
514-
}
515-
}
507+
func (h TaskHandler) BulkCancel(ctx *gin.Context) {
508+
filter, err := qf.New(ctx,
509+
[]qf.Assert{
510+
{Field: "id", Kind: qf.LITERAL},
511+
{Field: "name", Kind: qf.STRING},
512+
{Field: "locator", Kind: qf.STRING},
513+
{Field: "kind", Kind: qf.STRING},
514+
{Field: "addon", Kind: qf.STRING},
515+
{Field: "state", Kind: qf.STRING},
516+
{Field: "application.id", Kind: qf.STRING},
517+
})
518+
if err != nil {
519+
_ = ctx.Error(err)
520+
return
521+
}
522+
filter = filter.Renamed("application.id", "applicationId")
523+
db := h.DB(ctx)
524+
db = db.Model(&model.Task{})
525+
db = filter.Where(db)
526+
matched := []*model.Task{}
527+
err = db.Find(&matched).Error
528+
if err != nil {
529+
_ = ctx.Error(err)
530+
return
531+
}
532+
db = h.DB(ctx)
533+
rtx := RichContext(ctx)
534+
for _, m := range matched {
535+
err := rtx.TaskManager.Cancel(db, m.ID)
536+
if err != nil {
537+
_ = ctx.Error(err)
538+
return
539+
}
540+
}
516541

517-
h.Status(ctx, http.StatusAccepted)
542+
h.Status(ctx, http.StatusAccepted)
518543
}
519544

520-
521545
// BucketGet godoc
522546
// @summary Get bucket content by ID and path.
523547
// @description Get bucket content by ID and path.

binding/task.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,10 @@ func (h *Task) List() (list []api.Task, err error) {
3030
return
3131
}
3232

33-
// CancelMultipleTasks - Cancel multiple tasks by their IDs.
34-
func (h *Task) CancelMultipleTasks(ids []uint) (err error) {
35-
err = h.client.Put(api.TaskCancelListRoot, ids)
36-
return
33+
// BulkCancel - Cancel tasks matched by filter.
34+
func (h *Task) BulkCancel(filter Filter) (err error) {
35+
err = h.client.Put(api.TasksCancelRoot, 0, filter.Param())
36+
return
3737
}
3838

3939
// Update a Task.

test/api/task/api_test.go

+11
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import (
44
"testing"
55
"time"
66

7+
"github.com/konveyor/tackle2-hub/binding"
8+
"github.com/konveyor/tackle2-hub/binding/filter"
79
"github.com/konveyor/tackle2-hub/test/assert"
810
)
911

@@ -110,3 +112,12 @@ func TestTaskList(t *testing.T) {
110112
assert.Must(t, Task.Delete(r.ID))
111113
}
112114
}
115+
116+
func TestBulkCancel(t *testing.T) {
117+
f := binding.Filter{}
118+
f.And("id").Eq(filter.Any{1, 2, 3})
119+
err := Task.BulkCancel(f)
120+
if err != nil {
121+
t.Errorf(err.Error())
122+
}
123+
}

0 commit comments

Comments
 (0)