|
|
|
@ -111,29 +111,29 @@ func ProcessRequest(script string, params map[string]interface{}) (response map[ |
|
|
|
case vm.Interrupt <- func() { |
|
|
|
case vm.Interrupt <- func() { |
|
|
|
panic(errors.New("some code took to long! Stopping after timeout")) |
|
|
|
panic(errors.New("some code took to long! Stopping after timeout")) |
|
|
|
}: |
|
|
|
}: |
|
|
|
// Interrupt sent successfully
|
|
|
|
// Interrupt sent
|
|
|
|
case <-timeoutDone: |
|
|
|
case <-timeoutDone: |
|
|
|
// Script completed before timeout, timer already stopped
|
|
|
|
// Script already completed
|
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
case <-timeoutDone: |
|
|
|
case <-timeoutDone: |
|
|
|
// Script completed before timeout, stop timer
|
|
|
|
// Script completed before timeout, ensure timer is stopped
|
|
|
|
if !timeoutTimer.Stop() { |
|
|
|
timeoutTimer.Stop() |
|
|
|
<-timeoutTimer.C |
|
|
|
// Drain timer channel if needed (non-blocking)
|
|
|
|
|
|
|
|
select { |
|
|
|
|
|
|
|
case <-timeoutTimer.C: |
|
|
|
|
|
|
|
default: |
|
|
|
} |
|
|
|
} |
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
}() |
|
|
|
}() |
|
|
|
|
|
|
|
|
|
|
|
defer func() { |
|
|
|
defer func() { |
|
|
|
// Signal timeout goroutine to exit and stop timer
|
|
|
|
// Signal timeout goroutine to exit by closing channel
|
|
|
|
close(timeoutDone) |
|
|
|
close(timeoutDone) |
|
|
|
if !timeoutTimer.Stop() { |
|
|
|
|
|
|
|
select { |
|
|
|
// Stop timer - this is safe even if it already fired
|
|
|
|
case <-timeoutTimer.C: |
|
|
|
// We don't need to drain the channel here as goroutine handles it
|
|
|
|
default: |
|
|
|
timeoutTimer.Stop() |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if r := recover(); r != nil { |
|
|
|
if r := recover(); r != nil { |
|
|
|
switch x := r.(type) { |
|
|
|
switch x := r.(type) { |
|
|
|
case error: |
|
|
|
case error: |
|
|
|
|