Skip to content

Commit

Permalink
APPS-1397 Add cancel current backup endpoint (#284)
Browse files Browse the repository at this point in the history
* rollback API checnges for restore job id

* set restore id explicitly int64

* add cancel test

* add cancel funciton and test

* add WrappedBackupHandler interface (name in progress)

* run cancel

* linter

* add unit test for cancellation

* update openapi

* use post

* clean code

* clean code

* add comments

* add comments

* use context.CancelFunc

* add logs on cancel

* don't skip cancelled errors
  • Loading branch information
korotkov-aerospike authored Dec 16, 2024
1 parent 6c1f206 commit 7e77999
Show file tree
Hide file tree
Showing 16 changed files with 341 additions and 25 deletions.
43 changes: 40 additions & 3 deletions docs/docs.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,41 @@ const docTemplate = `{
}
}
},
"/v1/backups/cancel/{name}": {
"post": {
"tags": [
"Backup"
],
"summary": "Cancel current backup.",
"operationId": "cancelCurrentBackup",
"parameters": [
{
"type": "string",
"description": "Backup routine name",
"name": "name",
"in": "path",
"required": true
}
],
"responses": {
"202": {
"description": "Accepted"
},
"404": {
"description": "Not Found",
"schema": {
"type": "string"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"type": "string"
}
}
}
}
},
"/v1/backups/currentBackup/{name}": {
"get": {
"produces": [
Expand Down Expand Up @@ -1229,6 +1264,7 @@ const docTemplate = `{
"parameters": [
{
"type": "integer",
"format": "int64",
"description": "Restore job ID",
"name": "jobID",
"in": "path",
Expand Down Expand Up @@ -1288,7 +1324,7 @@ const docTemplate = `{
"202": {
"description": "Restore operation job id",
"schema": {
"type": "integer"
"type": "int64"
}
},
"400": {
Expand Down Expand Up @@ -1331,7 +1367,7 @@ const docTemplate = `{
"202": {
"description": "Restore operation job id",
"schema": {
"type": "integer"
"type": "int64"
}
},
"400": {
Expand Down Expand Up @@ -1362,6 +1398,7 @@ const docTemplate = `{
"parameters": [
{
"type": "integer",
"format": "int64",
"description": "Job ID to retrieve the status",
"name": "jobId",
"in": "path",
Expand Down Expand Up @@ -1410,7 +1447,7 @@ const docTemplate = `{
"202": {
"description": "Restore operation job id",
"schema": {
"type": "integer"
"type": "int64"
}
},
"400": {
Expand Down
47 changes: 47 additions & 0 deletions docs/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,48 @@
"tags" : [ "System" ]
}
},
"/v1/backups/cancel/{name}" : {
"post" : {
"operationId" : "cancelCurrentBackup",
"parameters" : [ {
"description" : "Backup routine name",
"in" : "path",
"name" : "name",
"required" : true,
"schema" : {
"type" : "string"
}
} ],
"responses" : {
"202" : {
"content" : { },
"description" : "Accepted"
},
"404" : {
"content" : {
"*/*" : {
"schema" : {
"type" : "string"
}
}
},
"description" : "Not Found"
},
"500" : {
"content" : {
"*/*" : {
"schema" : {
"type" : "string"
}
}
},
"description" : "Internal Server Error"
}
},
"summary" : "Cancel current backup.",
"tags" : [ "Backup" ]
}
},
"/v1/backups/currentBackup/{name}" : {
"get" : {
"operationId" : "getCurrentBackup",
Expand Down Expand Up @@ -1375,6 +1417,7 @@
"name" : "jobID",
"required" : true,
"schema" : {
"format" : "int64",
"type" : "integer"
}
} ],
Expand Down Expand Up @@ -1443,6 +1486,7 @@
"content" : {
"*/*" : {
"schema" : {
"format" : "int64",
"type" : "integer"
}
}
Expand Down Expand Up @@ -1494,6 +1538,7 @@
"content" : {
"*/*" : {
"schema" : {
"format" : "int64",
"type" : "integer"
}
}
Expand Down Expand Up @@ -1535,6 +1580,7 @@
"name" : "jobId",
"required" : true,
"schema" : {
"format" : "int64",
"type" : "integer"
}
} ],
Expand Down Expand Up @@ -1584,6 +1630,7 @@
"content" : {
"*/*" : {
"schema" : {
"format" : "int64",
"type" : "integer"
}
}
Expand Down
34 changes: 34 additions & 0 deletions docs/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,35 @@ paths:
summary: Readiness endpoint.
tags:
- System
/v1/backups/cancel/{name}:
post:
operationId: cancelCurrentBackup
parameters:
- description: Backup routine name
in: path
name: name
required: true
schema:
type: string
responses:
"202":
content: {}
description: Accepted
"404":
content:
'*/*':
schema:
type: string
description: Not Found
"500":
content:
'*/*':
schema:
type: string
description: Internal Server Error
summary: Cancel current backup.
tags:
- Backup
/v1/backups/currentBackup/{name}:
get:
operationId: getCurrentBackup
Expand Down Expand Up @@ -953,6 +982,7 @@ paths:
name: jobID
required: true
schema:
format: int64
type: integer
responses:
"200":
Expand Down Expand Up @@ -997,6 +1027,7 @@ paths:
content:
'*/*':
schema:
format: int64
type: integer
description: Restore operation job id
"400":
Expand Down Expand Up @@ -1030,6 +1061,7 @@ paths:
content:
'*/*':
schema:
format: int64
type: integer
description: Restore operation job id
"400":
Expand Down Expand Up @@ -1057,6 +1089,7 @@ paths:
name: jobId
required: true
schema:
format: int64
type: integer
responses:
"200":
Expand Down Expand Up @@ -1090,6 +1123,7 @@ paths:
content:
'*/*':
schema:
format: int64
type: integer
description: Restore operation job id
"400":
Expand Down
34 changes: 34 additions & 0 deletions internal/server/handlers/backup.go
Original file line number Diff line number Diff line change
Expand Up @@ -331,3 +331,37 @@ func (s *Service) GetCurrentBackupInfo(w http.ResponseWriter, r *http.Request) {
)
}
}

// CancelCurrentBackup
// @Summary Cancel current backup.
// @ID cancelCurrentBackup
// @Tags Backup
// @Param name path string true "Backup routine name"
// @Router /v1/backups/cancel/{name} [post]
// @Success 202
// @Failure 404 {string} string
// @Failure 500 {string} string
func (s *Service) CancelCurrentBackup(w http.ResponseWriter, r *http.Request) {
hLogger := s.logger.With(slog.String("handler", "CancelCurrentBackup"))

routineName := mux.Vars(r)["name"]
if routineName == "" {
hLogger.Error("routine name required")
http.Error(w, "routine name required", http.StatusBadRequest)
return
}

handler, found := s.handlerHolder[routineName]
if !found {
hLogger.Error("unknown routine name",
slog.String("name", routineName),
)
http.Error(w, "unknown routine name "+routineName, http.StatusNotFound)
return
}

handler.Cancel()

w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusAccepted)
}
39 changes: 39 additions & 0 deletions internal/server/handlers/backup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@ func TestService_ScheduleFullBackup(t *testing.T) {
}
}

//nolint:dupl
func TestService_GetCurrentBackupInfo(t *testing.T) {
t.Parallel()
h := newServiceMock(t)
Expand Down Expand Up @@ -273,3 +274,41 @@ func TestService_GetCurrentBackupInfo(t *testing.T) {
End()
}
}

//nolint:dupl
func TestService_CancelRunningBackup(t *testing.T) {
t.Parallel()
h := newServiceMock(t)
router := mux.NewRouter()
router.HandleFunc(
"/backups/cancel/{name}",
h.CancelCurrentBackup,
).Methods(http.MethodPost)

const name = testRoutineName

testCases := []struct {
method string
statusCode int
name string
}{
{http.MethodPost, http.StatusNotFound, name},
{http.MethodPost, http.StatusNotFound, ""},
{http.MethodGet, http.StatusMethodNotAllowed, name},
{http.MethodConnect, http.StatusMethodNotAllowed, name},
{http.MethodDelete, http.StatusMethodNotAllowed, name},
{http.MethodPatch, http.StatusMethodNotAllowed, name},
{http.MethodPut, http.StatusMethodNotAllowed, name},
{http.MethodTrace, http.StatusMethodNotAllowed, name},
}

for _, tt := range testCases {
apitest.New().
Handler(router).
Method(tt.method).
URL(fmt.Sprintf("/backups/cancel/%s", tt.name)).
Expect(t).
Status(tt.statusCode).
End()
}
}
10 changes: 5 additions & 5 deletions internal/server/handlers/restore.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import (
// @Router /v1/restore/full [post]
// @Accept json
// @Param request body dto.RestoreRequest true "Restore request details"
// @Success 202 {integer} int "Restore operation job id"
// @Success 202 {int64} int64 "Restore operation job id"
// @Failure 400 {string} string
// @Failure 405 {string} string
func (s *Service) RestoreFullHandler(w http.ResponseWriter, r *http.Request) {
Expand Down Expand Up @@ -76,7 +76,7 @@ func (s *Service) RestoreFullHandler(w http.ResponseWriter, r *http.Request) {
// @Router /v1/restore/incremental [post]
// @Accept json
// @Param request body dto.RestoreRequest true "Restore request details"
// @Success 202 {integer} int "Restore operation job id"
// @Success 202 {int64} int64 "Restore operation job id"
// @Failure 400 {string} string
// @Failure 405 {string} string
func (s *Service) RestoreIncrementalHandler(w http.ResponseWriter, r *http.Request) {
Expand Down Expand Up @@ -131,7 +131,7 @@ func (s *Service) RestoreIncrementalHandler(w http.ResponseWriter, r *http.Reque
// @Router /v1/restore/timestamp [post]
// @Accept json
// @Param request body dto.RestoreTimestampRequest true "Restore request details"
// @Success 202 {integer} int "Restore operation job id"
// @Success 202 {int64} int64 "Restore operation job id"
// @Failure 400 {string} string
// @Failure 405 {string} string
func (s *Service) RestoreByTimeHandler(w http.ResponseWriter, r *http.Request) {
Expand Down Expand Up @@ -185,7 +185,7 @@ func (s *Service) RestoreByTimeHandler(w http.ResponseWriter, r *http.Request) {
// @ID restoreStatus
// @Tags Restore
// @Produce json
// @Param jobId path int true "Job ID to retrieve the status"
// @Param jobId path int true "Job ID to retrieve the status" format(int64)
// @Router /v1/restore/status/{jobId} [get]
// @Success 200 {object} dto.RestoreJobStatus "Restore job status details"
// @Failure 400 {string} string
Expand Down Expand Up @@ -304,7 +304,7 @@ func (s *Service) RetrieveConfig(w http.ResponseWriter, r *http.Request) {
// @ID cancelRestore
// @Tags Restore
// @Router /v1/restore/cancel/{jobID} [post]
// @Param jobID path int true "Restore job ID"
// @Param jobID path int true "Restore job ID" format(int64)
// @Success 200 {string} string "Restore job canceled successfully"
// @Failure 400 {string} string "Invalid job ID"
// @Failure 404 {string} string "Job not found"
Expand Down
Loading

0 comments on commit 7e77999

Please sign in to comment.