Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow desktop runner Interrupt to be called multiple times #1344

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions ee/desktop/runner/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ type DesktopUsersProcessesRunner struct {
// menuRefreshInterval is the interval on which the desktop menu will be refreshed
menuRefreshInterval time.Duration
interrupt chan struct{}
interrupted bool
// uidProcs is a map of uid to desktop process
uidProcs map[string]processRecord
// procsWg is a WaitGroup to wait for all desktop processes to finish during an interrupt
Expand Down Expand Up @@ -222,6 +223,13 @@ func (r *DesktopUsersProcessesRunner) Execute() error {
// Interrupt stops creating launcher desktop processes and kills any existing ones.
// It also signals the execute loop to exit, so new desktop processes cease to spawn.
func (r *DesktopUsersProcessesRunner) Interrupt(_ error) {
// Only perform shutdown tasks on first call to interrupt -- no need to repeat on potential extra calls.
if r.interrupted {
return
}

r.interrupted = true

// Tell the execute loop to stop checking, and exit
r.interrupt <- struct{}{}

Expand Down
30 changes: 29 additions & 1 deletion ee/desktop/runner/runner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ func TestDesktopUserProcessRunner_Execute(t *testing.T) {
assert.NoError(t, r.Execute())
}()

// let is run a few interval
// let it run a few intervals
time.Sleep(r.updateInterval * 3)
r.Interrupt(nil)

Expand Down Expand Up @@ -185,6 +185,34 @@ func TestDesktopUserProcessRunner_Execute(t *testing.T) {
p.Process.Wait()
}
})

// Confirm we can call Interrupt multiple times without blocking
interruptComplete := make(chan struct{})
expectedInterrupts := 3
for i := 0; i < expectedInterrupts; i += 1 {
go func() {
r.Interrupt(nil)
interruptComplete <- struct{}{}
}()
}

receivedInterrupts := 0
for {
if receivedInterrupts >= expectedInterrupts {
break
}

select {
case <-interruptComplete:
receivedInterrupts += 1
continue
case <-time.After(5 * time.Second):
t.Errorf("could not call interrupt multiple times and return within 5 seconds -- received %d interrupts before timeout", receivedInterrupts)
t.FailNow()
}
}

require.Equal(t, expectedInterrupts, receivedInterrupts)
})
}
}
Expand Down
Loading