main.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 main
 16  
 17  import (
 18  	"context"
 19  	"fmt"
 20  	"net/http"
 21  	"os"
 22  	"os/signal"
 23  	"syscall"
 24  	"time"
 25  
 26  	"k8s.io/klog/v2"
 27  
 28  	"github.com/alibaba/OpenSandbox/sandbox-k8s/internal/task-executor/config"
 29  	"github.com/alibaba/OpenSandbox/sandbox-k8s/internal/task-executor/manager"
 30  	"github.com/alibaba/OpenSandbox/sandbox-k8s/internal/task-executor/runtime"
 31  	"github.com/alibaba/OpenSandbox/sandbox-k8s/internal/task-executor/server"
 32  	store "github.com/alibaba/OpenSandbox/sandbox-k8s/internal/task-executor/storage"
 33  )
 34  
 35  func main() {
 36  	// Load configuration
 37  	cfg := config.NewConfig()
 38  	cfg.LoadFromEnv()
 39  	cfg.LoadFromFlags()
 40  	if err := cfg.InitKlog(); err != nil {
 41  		fmt.Println("failed to init klog")
 42  		os.Exit(1)
 43  	}
 44  	klog.InfoS("task-executor starting", "dataDir", cfg.DataDir, "listenAddr", cfg.ListenAddr, "sidecarMode", cfg.EnableSidecarMode)
 45  
 46  	// Initialize TaskStore
 47  	taskStore, err := store.NewFileStore(cfg.DataDir)
 48  	if err != nil {
 49  		klog.ErrorS(err, "failed to create task store")
 50  		os.Exit(1)
 51  	}
 52  	klog.InfoS("task store initialized", "dataDir", cfg.DataDir)
 53  
 54  	// Initialize Executor
 55  	exec, err := runtime.NewExecutor(cfg)
 56  	if err != nil {
 57  		klog.ErrorS(err, "failed to create executor")
 58  		os.Exit(1)
 59  	}
 60  
 61  	// Initialize TaskManager
 62  	taskManager, err := manager.NewTaskManager(cfg, taskStore, exec)
 63  	if err != nil {
 64  		klog.ErrorS(err, "failed to create task manager")
 65  		os.Exit(1)
 66  	}
 67  
 68  	// Start TaskManager
 69  	taskManager.Start(context.Background())
 70  	klog.InfoS("task manager started")
 71  
 72  	// Initialize HTTP Handler and Router
 73  	handler := server.NewHandler(taskManager, cfg)
 74  	router := server.NewRouter(handler)
 75  
 76  	// Create HTTP Server
 77  	svr := &http.Server{
 78  		Addr:         cfg.ListenAddr,
 79  		Handler:      router,
 80  		ReadTimeout:  cfg.ReadTimeout,
 81  		WriteTimeout: cfg.WriteTimeout,
 82  	}
 83  
 84  	// Start HTTP server in goroutine
 85  	go func() {
 86  		klog.InfoS("HTTP server listening", "address", cfg.ListenAddr)
 87  		if err := svr.ListenAndServe(); err != nil && err != http.ErrServerClosed {
 88  			klog.ErrorS(err, "HTTP server error")
 89  			os.Exit(1)
 90  		}
 91  	}()
 92  
 93  	// Wait for interrupt signal
 94  	quit := make(chan os.Signal, 1)
 95  	signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
 96  	<-quit
 97  
 98  	klog.InfoS("shutting down task-executor gracefully...")
 99  
100  	// Shutdown context with timeout
101  	shutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), 30*time.Second)
102  	defer shutdownCancel()
103  
104  	// 1. Stop HTTP server first
105  	if err := svr.Shutdown(shutdownCtx); err != nil {
106  		klog.ErrorS(err, "HTTP server shutdown error")
107  	} else {
108  		klog.InfoS("HTTP server stopped")
109  	}
110  
111  	// 2. Stop TaskManager
112  	taskManager.Stop()
113  	klog.InfoS("task manager stopped")
114  
115  	klog.InfoS("task-executor stopped successfully")
116  }