Manager: allow cancelling worker state change requests

A worker state change request can now be cancelled by requesting the worker
to go to its current state. In other words, a previously requested change
`A → B` can be cancelled by requesting the worker goes to state `A`.

Previously this would simply overwrite the last request, resulting in a
requested state change `A → A`. Having this non-lazy would even interrupt
the currently running task.
This commit is contained in:
Sybren A. Stüvel 2022-06-02 12:43:16 +02:00
parent 3ce225b6e1
commit 678308fb6d
2 changed files with 58 additions and 4 deletions

View File

@ -81,16 +81,24 @@ func (f *Flamenco) RequestWorkerStatusChange(e echo.Context, workerUUID string)
return sendAPIError(e, http.StatusInternalServerError, "error fetching worker: %v", err) return sendAPIError(e, http.StatusInternalServerError, "error fetching worker: %v", err)
} }
// Store the status change.
logger = logger.With(). logger = logger.With().
Str("status", string(dbWorker.Status)). Str("status", string(dbWorker.Status)).
Str("requested", string(change.Status)). Str("requested", string(change.Status)).
Bool("lazy", change.IsLazy). Bool("lazy", change.IsLazy).
Logger() Logger()
logger.Info().Msg("worker status change requested") logger.Info().Msg("worker status change requested")
dbWorker.StatusRequested = change.Status
dbWorker.LazyStatusRequest = change.IsLazy if dbWorker.Status == change.Status {
// Requesting that the worker should go to its current status basically
// means cancelling any previous status change request.
dbWorker.StatusRequested = ""
dbWorker.LazyStatusRequest = false
} else {
dbWorker.StatusRequested = change.Status
dbWorker.LazyStatusRequest = change.IsLazy
}
// Store the status change.
if err := f.persist.SaveWorker(e.Request().Context(), dbWorker); err != nil { if err := f.persist.SaveWorker(e.Request().Context(), dbWorker); err != nil {
logger.Error().Err(err).Msg("error saving worker after status change request") logger.Error().Err(err).Msg("error saving worker after status change request")
return sendAPIError(e, http.StatusInternalServerError, "error saving worker: %v", err) return sendAPIError(e, http.StatusInternalServerError, "error saving worker: %v", err)

View File

@ -162,3 +162,49 @@ func TestRequestWorkerStatusChange(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
assertResponseEmpty(t, echo) assertResponseEmpty(t, echo)
} }
func TestRequestWorkerStatusChangeRevert(t *testing.T) {
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
mf := newMockedFlamenco(mockCtrl)
worker := testWorker()
// Mimick that a status change request to 'asleep' was already performed.
worker.StatusRequested = api.WorkerStatusAsleep
worker.LazyStatusRequest = true
workerUUID := worker.UUID
currentStatus := worker.Status
mf.persistence.EXPECT().FetchWorker(gomock.Any(), workerUUID).Return(&worker, nil)
// Perform a request to go to the current worker status. This should cancel
// the previous status change request.
requestStatus := currentStatus
savedWorker := worker
savedWorker.StatusRequested = ""
savedWorker.LazyStatusRequest = false
mf.persistence.EXPECT().SaveWorker(gomock.Any(), &savedWorker).Return(nil)
// Expect a broadcast of the change
mf.broadcaster.EXPECT().BroadcastWorkerUpdate(api.SocketIOWorkerUpdate{
Id: worker.UUID,
Nickname: worker.Name,
Status: currentStatus,
Updated: worker.UpdatedAt,
Version: worker.Software,
StatusChange: nil,
})
echo := mf.prepareMockedJSONRequest(api.WorkerStatusChangeRequest{
Status: requestStatus,
// This shouldn't matter; requesting the current status should simply erase
// the previous status change request.
IsLazy: true,
})
err := mf.flamenco.RequestWorkerStatusChange(echo, workerUUID)
assert.NoError(t, err)
assertResponseEmpty(t, echo)
}