ctrl.go
1 // Copyright 2025 Alibaba Group Holding Ltd. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package runtime 16 17 import ( 18 "context" 19 "database/sql" 20 "fmt" 21 "sync" 22 "time" 23 24 "k8s.io/apimachinery/pkg/util/wait" 25 26 "github.com/alibaba/opensandbox/execd/pkg/jupyter" 27 ) 28 29 var kernelWaitingBackoff = wait.Backoff{ 30 Steps: 60, 31 Duration: 500 * time.Millisecond, 32 Factor: 1.5, 33 Jitter: 0.1, 34 } 35 36 // Controller manages code execution across runtimes. 37 type Controller struct { 38 baseURL string 39 token string 40 mu sync.RWMutex 41 jupyterClientMap sync.Map // map[sessionID]*jupyterKernel 42 defaultLanguageSessions sync.Map // map[Language]string 43 commandClientMap sync.Map // map[sessionID]*commandKernel 44 bashSessionClientMap sync.Map // map[sessionID]*bashSession 45 ptySessionMap sync.Map // map[sessionID]*ptySession 46 db *sql.DB 47 dbOnce sync.Once 48 } 49 50 type jupyterKernel struct { 51 mu sync.Mutex 52 kernelID string 53 client *jupyter.Client 54 language Language 55 } 56 57 type commandKernel struct { 58 pid int 59 stdoutPath string 60 stderrPath string 61 startedAt time.Time 62 finishedAt *time.Time 63 exitCode *int 64 errMsg string 65 running bool 66 isBackground bool 67 content string 68 } 69 70 // NewController creates a runtime controller. 71 func NewController(baseURL, token string) *Controller { 72 return &Controller{ 73 baseURL: baseURL, 74 token: token, 75 } 76 } 77 78 // Execute dispatches a request to the correct backend. 79 func (c *Controller) Execute(request *ExecuteCodeRequest) error { 80 var cancel context.CancelFunc 81 var ctx context.Context 82 if request.Timeout > 0 { 83 ctx, cancel = context.WithTimeout(context.Background(), request.Timeout) 84 } else { 85 ctx, cancel = context.WithCancel(context.Background()) 86 } 87 88 switch request.Language { 89 case Command: 90 defer cancel() 91 return c.runCommand(ctx, request) 92 case BackgroundCommand: 93 return c.runBackgroundCommand(ctx, cancel, request) 94 case Bash, Python, Java, JavaScript, TypeScript, Go: 95 defer cancel() 96 return c.runJupyter(ctx, request) 97 case SQL: 98 defer cancel() 99 return c.runSQL(ctx, request) 100 default: 101 defer cancel() 102 return fmt.Errorf("unknown language: %s", request.Language) 103 } 104 }