diff --git a/components/execd/pkg/web/controller/command.go b/components/execd/pkg/web/controller/command.go index fba9d18ea..acf4bbe1c 100644 --- a/components/execd/pkg/web/controller/command.go +++ b/components/execd/pkg/web/controller/command.go @@ -22,7 +22,6 @@ import ( "sync" "time" - "github.com/alibaba/opensandbox/execd/pkg/flag" "github.com/alibaba/opensandbox/execd/pkg/jupyter/execute" "github.com/alibaba/opensandbox/execd/pkg/runtime" "github.com/alibaba/opensandbox/execd/pkg/telemetry" @@ -113,12 +112,6 @@ func (c *CodeInterpretingController) RunCommand() { } waitForExecutionComplete(ctx, completeCh) - - // Keep the SSE connection alive briefly so clients can read all - // buffered events and downstream components (e.g. egress sidecar) - // have time to synchronise state changes that were triggered - // during command execution. - time.Sleep(flag.ApiGracefulShutdownTimeout) } // InterruptCommand stops a running shell command session. diff --git a/components/execd/pkg/web/controller/command_test.go b/components/execd/pkg/web/controller/command_test.go index 74735963a..aa59ab527 100644 --- a/components/execd/pkg/web/controller/command_test.go +++ b/components/execd/pkg/web/controller/command_test.go @@ -20,7 +20,9 @@ import ( "net/http/httptest" "reflect" "testing" + "time" + "github.com/alibaba/opensandbox/execd/pkg/flag" "github.com/alibaba/opensandbox/execd/pkg/runtime" "github.com/alibaba/opensandbox/execd/pkg/web/model" "github.com/stretchr/testify/require" @@ -88,3 +90,30 @@ func TestGetBackgroundCommandOutput_MissingID(t *testing.T) { require.Equal(t, model.ErrorCodeMissingQuery, resp.Code) require.Equal(t, "missing command execution id", resp.Message) } + +func TestRunCommandReturnsBeforeGracefulShutdownTimeoutAfterImmediateComplete(t *testing.T) { + previousRunner := codeRunner + previousTimeout := flag.ApiGracefulShutdownTimeout + codeRunner = &fakeCodeRunner{ + execute: func(request *runtime.ExecuteCodeRequest) error { + request.Hooks.OnExecuteComplete(5 * time.Millisecond) + return nil + }, + } + flag.ApiGracefulShutdownTimeout = 200 * time.Millisecond + t.Cleanup(func() { + codeRunner = previousRunner + flag.ApiGracefulShutdownTimeout = previousTimeout + }) + + body := []byte(`{"command":"echo hi"}`) + ctx, w := newTestContext(http.MethodPost, "/command", body) + ctrl := NewCodeInterpretingController(ctx) + + start := time.Now() + ctrl.RunCommand() + elapsed := time.Since(start) + + require.Equal(t, http.StatusOK, w.Code) + require.Less(t, elapsed, flag.ApiGracefulShutdownTimeout/2) +}