Allow sending a termination signal even if another power action is being processed

This commit is contained in:
Dane Everitt 2020-08-13 20:37:35 -07:00
parent cf1c671e68
commit 5fcec86e98
No known key found for this signature in database
GPG Key ID: EEA66103B3D71F53

View File

@ -53,27 +53,44 @@ func (s *Server) HandlePowerAction(action PowerAction, waitSeconds ...int) error
s.powerLock = semaphore.NewWeighted(1) s.powerLock = semaphore.NewWeighted(1)
} }
// Determines if we should wait for the lock or not. If a value greater than 0 is passed // Only attempt to acquire a lock on the process if this is not a termination event. We want to
// into this function we will wait that long for a lock to be acquired. // just allow those events to pass right through for good reason. If a server is currently trying
if len(waitSeconds) > 0 && waitSeconds[0] != 0 { // to process a power action but has gotten stuck you still should be able to pass through the
ctx, _ := context.WithTimeout(context.Background(), time.Second*time.Duration(waitSeconds[0])) // terminate event. The good news here is that doing that oftentimes will get the stuck process to
// Attempt to acquire a lock on the power action lock for up to 30 seconds. If more // move again, and naturally continue through the process.
// time than that passes an error will be propagated back up the chain and this if action != PowerActionTerminate {
// request will be aborted. // Determines if we should wait for the lock or not. If a value greater than 0 is passed
if err := s.powerLock.Acquire(ctx, 1); err != nil { // into this function we will wait that long for a lock to be acquired.
return errors.WithMessage(err, "could not acquire lock on power state") if len(waitSeconds) > 0 && waitSeconds[0] != 0 {
ctx, _ := context.WithTimeout(context.Background(), time.Second*time.Duration(waitSeconds[0]))
// Attempt to acquire a lock on the power action lock for up to 30 seconds. If more
// time than that passes an error will be propagated back up the chain and this
// request will be aborted.
if err := s.powerLock.Acquire(ctx, 1); err != nil {
return errors.WithMessage(err, "could not acquire lock on power state")
}
} else {
// If no wait duration was provided we will attempt to immediately acquire the lock
// and bail out with a context deadline error if it is not acquired immediately.
if ok := s.powerLock.TryAcquire(1); !ok {
return errors.WithMessage(context.DeadlineExceeded, "could not acquire lock on power state")
}
} }
// Release the lock once the process being requested has finished executing.
defer s.powerLock.Release(1)
} else { } else {
// If no wait duration was provided we will attempt to immediately acquire the lock // Still try to acquire the lock if terminating and it is available, just so that other power
// and bail out with a context deadline error if it is not acquired immediately. // actions are blocked until it has completed. However, if it is unavailable we won't stop
if ok := s.powerLock.TryAcquire(1); !ok { // the entire process.
return errors.WithMessage(context.DeadlineExceeded, "could not acquire lock on power state") if ok := s.powerLock.TryAcquire(1); ok {
// If we managed to acquire the lock be sure to released it once this process is completed.
defer s.powerLock.Release(1)
} }
} }
// Release the lock once the process being requested has finished executing. // Ensure the server data is properly synced before attempting to start the process, and that there
defer s.powerLock.Release(1) // is enough disk space available.
if action.IsStart() { if action.IsStart() {
s.Log().Info("syncing server configuration with panel") s.Log().Info("syncing server configuration with panel")
if err := s.Sync(); err != nil { if err := s.Sync(); err != nil {