refactor(tests): rename and consolidate input building functions for clarity
- Renamed `buildInput` to `buildLastUserMessageJSONL` to better reflect its purpose of constructing JSONL from the last user message. - Updated test cases to use the new function, ensuring they accurately verify the behavior of skipping system messages and only including the last user message. - Removed the now redundant `buildFirstRequestJSONL` function, streamlining the input building process in the Claude command tests.
This commit is contained in:
parent
14426327dd
commit
890ca3e25a
5 changed files with 287 additions and 131 deletions
|
|
@ -72,7 +72,7 @@ func (r *ClaudeRunner) buildCommand(ctx context.Context, req *types.StreamReques
|
|||
|
||||
env := buildEnv(req, p)
|
||||
args := buildArgs(req, r, p, isContinuation, assistantID, chatID)
|
||||
inputJSONL := buildInput(req.Messages, isContinuation)
|
||||
inputJSONL := buildLastUserMessageJSONL(req.Messages)
|
||||
|
||||
var systemPrompt string
|
||||
envPrompt := buildSandboxEnvPrompt(p, workDir)
|
||||
|
|
@ -236,13 +236,6 @@ func buildArgs(req *types.StreamRequest, r *ClaudeRunner, p platform, isContinua
|
|||
return args
|
||||
}
|
||||
|
||||
func buildInput(messages []agentContext.Message, isContinuation bool) string {
|
||||
if isContinuation {
|
||||
return buildLastUserMessageJSONL(messages)
|
||||
}
|
||||
return buildFirstRequestJSONL(messages)
|
||||
}
|
||||
|
||||
func buildSandboxEnvPrompt(p platform, workDir string) string {
|
||||
osName := p.OS()
|
||||
if osName == "" {
|
||||
|
|
@ -323,32 +316,6 @@ func buildMCPAllowedTools(servers []types.MCPServer) string {
|
|||
return strings.Join(patterns, ",")
|
||||
}
|
||||
|
||||
// buildFirstRequestJSONL builds the input JSONL for a new (non-continuation)
|
||||
// Claude CLI session. Per the stream-json input protocol, only user messages
|
||||
// should be sent; Claude CLI manages its own assistant history internally.
|
||||
func buildFirstRequestJSONL(messages []agentContext.Message) string {
|
||||
var lines []string
|
||||
for _, msg := range messages {
|
||||
if msg.Role != "user" {
|
||||
continue
|
||||
}
|
||||
content := msg.Content
|
||||
if content == nil {
|
||||
content = ""
|
||||
}
|
||||
streamMsg := map[string]any{
|
||||
"type": "user",
|
||||
"message": map[string]any{
|
||||
"role": "user",
|
||||
"content": content,
|
||||
},
|
||||
}
|
||||
data, _ := json.Marshal(streamMsg)
|
||||
lines = append(lines, string(data))
|
||||
}
|
||||
return strings.Join(lines, "\n")
|
||||
}
|
||||
|
||||
func buildLastUserMessageJSONL(messages []agentContext.Message) string {
|
||||
for i := len(messages) - 1; i >= 0; i-- {
|
||||
if messages[i].Role == "user" {
|
||||
|
|
|
|||
|
|
@ -170,86 +170,43 @@ func TestBuildArgs_WhitelistOptions(t *testing.T) {
|
|||
assert.Contains(t, args, "--max-turns")
|
||||
}
|
||||
|
||||
// --- buildInput ---
|
||||
// --- buildLastUserMessageJSONL (was buildInput / buildFirstRequestJSONL) ---
|
||||
|
||||
func TestBuildInput_FirstRequest(t *testing.T) {
|
||||
msgs := []agentContext.Message{
|
||||
{Role: "user", Content: "hello"},
|
||||
{Role: "assistant", Content: "hi"},
|
||||
}
|
||||
result := buildInput(msgs, false)
|
||||
lines := strings.Split(strings.TrimSpace(result), "\n")
|
||||
assert.Len(t, lines, 1, "first request only includes user messages")
|
||||
assert.Contains(t, lines[0], "hello")
|
||||
assert.NotContains(t, result, "hi")
|
||||
}
|
||||
|
||||
func TestBuildInput_Continuation(t *testing.T) {
|
||||
msgs := []agentContext.Message{
|
||||
{Role: "user", Content: "first question"},
|
||||
{Role: "assistant", Content: "first answer"},
|
||||
{Role: "user", Content: "follow up"},
|
||||
}
|
||||
result := buildInput(msgs, true)
|
||||
var parsed map[string]any
|
||||
err := json.Unmarshal([]byte(result), &parsed)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "user", parsed["type"])
|
||||
msg, _ := parsed["message"].(map[string]any)
|
||||
assert.Equal(t, "follow up", msg["content"])
|
||||
}
|
||||
|
||||
// --- buildFirstRequestJSONL ---
|
||||
|
||||
func TestBuildFirstRequestJSONL_SkipsSystem(t *testing.T) {
|
||||
func TestBuildLastUserMessageJSONL_SkipsSystem(t *testing.T) {
|
||||
msgs := []agentContext.Message{
|
||||
{Role: "system", Content: "system prompt"},
|
||||
{Role: "user", Content: "hello"},
|
||||
}
|
||||
result := buildFirstRequestJSONL(msgs)
|
||||
lines := strings.Split(strings.TrimSpace(result), "\n")
|
||||
assert.Len(t, lines, 1, "system messages should be skipped")
|
||||
assert.Contains(t, lines[0], "hello")
|
||||
result := buildLastUserMessageJSONL(msgs)
|
||||
var parsed map[string]any
|
||||
err := json.Unmarshal([]byte(strings.TrimSpace(result)), &parsed)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "user", parsed["type"])
|
||||
msg, _ := parsed["message"].(map[string]any)
|
||||
assert.Equal(t, "hello", msg["content"])
|
||||
}
|
||||
|
||||
func TestBuildFirstRequestJSONL_OnlyUserMessages(t *testing.T) {
|
||||
func TestBuildLastUserMessageJSONL_OnlyLastUser(t *testing.T) {
|
||||
msgs := []agentContext.Message{
|
||||
{Role: "user", Content: "q1"},
|
||||
{Role: "assistant", Content: "a1"},
|
||||
{Role: "user", Content: "q2"},
|
||||
}
|
||||
result := buildFirstRequestJSONL(msgs)
|
||||
lines := strings.Split(strings.TrimSpace(result), "\n")
|
||||
assert.Len(t, lines, 2, "only user messages should be included")
|
||||
for _, line := range lines {
|
||||
var parsed map[string]any
|
||||
err := json.Unmarshal([]byte(line), &parsed)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "user", parsed["type"])
|
||||
msg, _ := parsed["message"].(map[string]any)
|
||||
assert.Equal(t, "user", msg["role"])
|
||||
}
|
||||
result := buildLastUserMessageJSONL(msgs)
|
||||
var parsed map[string]any
|
||||
err := json.Unmarshal([]byte(strings.TrimSpace(result)), &parsed)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "user", parsed["type"])
|
||||
msg, _ := parsed["message"].(map[string]any)
|
||||
assert.Equal(t, "q2", msg["content"])
|
||||
assert.NotContains(t, result, "q1")
|
||||
}
|
||||
|
||||
func TestBuildFirstRequestJSONL_AssistantOnlyMessages(t *testing.T) {
|
||||
msgs := []agentContext.Message{
|
||||
{Role: "assistant", Content: "a1"},
|
||||
{Role: "assistant", Content: "a2"},
|
||||
{Role: "assistant", Content: "a3"},
|
||||
{Role: "user", Content: "q1"},
|
||||
}
|
||||
result := buildFirstRequestJSONL(msgs)
|
||||
lines := strings.Split(strings.TrimSpace(result), "\n")
|
||||
assert.Len(t, lines, 1, "only the user message should be included")
|
||||
assert.Contains(t, lines[0], "q1")
|
||||
assert.NotContains(t, result, "a1")
|
||||
}
|
||||
|
||||
func TestBuildFirstRequestJSONL_NilContent(t *testing.T) {
|
||||
func TestBuildLastUserMessageJSONL_NilContent(t *testing.T) {
|
||||
msgs := []agentContext.Message{
|
||||
{Role: "user", Content: nil},
|
||||
}
|
||||
result := buildFirstRequestJSONL(msgs)
|
||||
result := buildLastUserMessageJSONL(msgs)
|
||||
var parsed map[string]any
|
||||
err := json.Unmarshal([]byte(strings.TrimSpace(result)), &parsed)
|
||||
require.NoError(t, err)
|
||||
|
|
|
|||
|
|
@ -58,10 +58,16 @@ var langs = map[string]string{
|
|||
"Force migrate": "强制更新数据表结构",
|
||||
"Migrate is not allowed on production mode.": "Migrate 不能再生产环境下使用",
|
||||
"Upgrade yao to latest version": "升级 yao 到最新版本",
|
||||
"Current version:": "当前版本:",
|
||||
"Latest version: ": "最新版本: ",
|
||||
"Checking latest version...": "正在检查最新版本...",
|
||||
"🎉Current version is the latest🎉": "🎉当前版本是最新的🎉",
|
||||
"Do you want to update to %s ? (y/n): ": "是否更新到 %s ? (y/n): ",
|
||||
"Invalid input": "输入错误",
|
||||
"Canceled upgrade": "已取消更新",
|
||||
"Downloading...": "正在下载...",
|
||||
"Progress:": "进度:",
|
||||
"Available assets:": "可用的制品:",
|
||||
"Error occurred while updating binary: %s": "更新二进制文件时出错: %s",
|
||||
"🎉Successfully updated to version: %s🎉": "🎉成功更新到版本: %s🎉",
|
||||
"Print all version information": "显示详细版本信息",
|
||||
|
|
@ -201,7 +207,7 @@ func init() {
|
|||
agentCmd,
|
||||
mcpCmd,
|
||||
robotCmd,
|
||||
// upgradeCmd,
|
||||
upgradeCmd,
|
||||
)
|
||||
// rootCmd.SetHelpCommand(helpCmd)
|
||||
rootCmd.PersistentFlags().StringVarP(&appPath, "app", "a", "", L("Application directory"))
|
||||
|
|
|
|||
240
cmd/upgrade.go
240
cmd/upgrade.go
|
|
@ -2,57 +2,257 @@ package cmd
|
|||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/blang/semver"
|
||||
"github.com/fatih/color"
|
||||
"github.com/rhysd/go-github-selfupdate/selfupdate"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/yaoapp/yao/share"
|
||||
)
|
||||
|
||||
const githubReleasesAPI = "https://api.github.com/repos/YaoApp/yao/releases/latest"
|
||||
|
||||
// githubRelease represents a GitHub release response
|
||||
type githubRelease struct {
|
||||
TagName string `json:"tag_name"`
|
||||
Name string `json:"name"`
|
||||
Prerelease bool `json:"prerelease"`
|
||||
Assets []githubAsset `json:"assets"`
|
||||
HTMLURL string `json:"html_url"`
|
||||
Body string `json:"body"`
|
||||
}
|
||||
|
||||
// githubAsset represents a single release asset
|
||||
type githubAsset struct {
|
||||
Name string `json:"name"`
|
||||
BrowserDownloadURL string `json:"browser_download_url"`
|
||||
Size int64 `json:"size"`
|
||||
}
|
||||
|
||||
var upgradeCmd = &cobra.Command{
|
||||
Use: "upgrade",
|
||||
Short: L("Upgrade yao app to latest version"),
|
||||
Long: L("Upgrade yao app to latest version"),
|
||||
Short: L("Upgrade yao to latest version"),
|
||||
Long: L("Upgrade yao to latest version"),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
Boot()
|
||||
latest, found, err := selfupdate.DetectLatest("yaoapp/yao")
|
||||
fmt.Printf("%s %s\n", color.WhiteString(L("Current version:")), color.CyanString(share.VERSION))
|
||||
fmt.Println(color.WhiteString(L("Checking latest version...")))
|
||||
|
||||
release, err := fetchLatestRelease()
|
||||
if err != nil {
|
||||
if err != nil {
|
||||
fmt.Println(color.RedString(L("Fatal: %s"), err.Error()))
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Println(color.RedString(L("Fatal: %s"), err.Error()))
|
||||
os.Exit(1)
|
||||
}
|
||||
currentVersion := semver.MustParse(share.VERSION)
|
||||
if !found || latest.Version.LTE(currentVersion) {
|
||||
|
||||
latestVersion := strings.TrimPrefix(release.TagName, "v")
|
||||
fmt.Printf("%s %s\n", color.WhiteString(L("Latest version: ")), color.GreenString(latestVersion))
|
||||
|
||||
if latestVersion == share.VERSION {
|
||||
fmt.Println(color.GreenString(L("🎉Current version is the latest🎉")))
|
||||
os.Exit(0)
|
||||
}
|
||||
fmt.Println(color.WhiteString(L("Do you want to update to %s ? (y/n): "), latest.Version))
|
||||
|
||||
assetName := buildAssetName(latestVersion)
|
||||
asset := findAsset(release.Assets, assetName)
|
||||
if asset == nil {
|
||||
fmt.Println(color.RedString(L("Fatal: %s"), fmt.Sprintf("asset not found: %s", assetName)))
|
||||
fmt.Printf("%s %s\n", color.WhiteString(L("Available assets:")), "")
|
||||
for _, a := range release.Assets {
|
||||
if !strings.HasSuffix(a.Name, ".sha256") && !strings.HasSuffix(a.Name, ".zip") && !strings.HasSuffix(a.Name, ".tar.gz") {
|
||||
fmt.Printf(" - %s\n", color.YellowString(a.Name))
|
||||
}
|
||||
}
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
fmt.Printf("%s %s\n", color.WhiteString(L("Do you want to update to %s ? (y/n): "), latestVersion), "")
|
||||
fmt.Print("> ")
|
||||
input, err := bufio.NewReader(os.Stdin).ReadString('\n')
|
||||
if err != nil {
|
||||
fmt.Println(color.RedString(L("Fatal: %s"), err.Error()))
|
||||
os.Exit(1)
|
||||
}
|
||||
if input != "y\n" && input != "Y\n" && input != "n\n" && input != "N\n" {
|
||||
fmt.Println(color.RedString(L("Fatal: %s"), L("Invalid input")))
|
||||
os.Exit(1)
|
||||
}
|
||||
if input == "n\n" || input == "N\n" {
|
||||
|
||||
input = strings.TrimSpace(input)
|
||||
if input != "y" && input != "Y" {
|
||||
fmt.Println(color.YellowString(L("Canceled upgrade")))
|
||||
return
|
||||
}
|
||||
|
||||
exe, err := os.Executable()
|
||||
if err != nil {
|
||||
fmt.Println(color.RedString(L("Fatal: %s"), err.Error()))
|
||||
os.Exit(1)
|
||||
}
|
||||
if err := selfupdate.UpdateTo(latest.AssetURL, exe); err != nil {
|
||||
exe, err = filepath.EvalSymlinks(exe)
|
||||
if err != nil {
|
||||
fmt.Println(color.RedString(L("Fatal: %s"), err.Error()))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
fmt.Printf("%s %s\n", color.WhiteString(L("Downloading...")), color.CyanString(asset.BrowserDownloadURL))
|
||||
if err := downloadAndReplace(asset.BrowserDownloadURL, exe); err != nil {
|
||||
fmt.Println(color.RedString(L("Error occurred while updating binary: %s"), err.Error()))
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Println(color.GreenString(L("🎉Successfully updated to version: %s🎉"), latest.Version))
|
||||
|
||||
fmt.Println(color.GreenString(L("🎉Successfully updated to version: %s🎉"), latestVersion))
|
||||
},
|
||||
}
|
||||
|
||||
// fetchLatestRelease fetches the latest release from GitHub API
|
||||
func fetchLatestRelease() (*githubRelease, error) {
|
||||
client := &http.Client{Timeout: 30 * time.Second}
|
||||
req, err := http.NewRequest("GET", githubReleasesAPI, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set("Accept", "application/vnd.github.v3+json")
|
||||
req.Header.Set("User-Agent", fmt.Sprintf("yao/%s", share.VERSION))
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("GitHub API returned status %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
var release githubRelease
|
||||
if err := json.NewDecoder(resp.Body).Decode(&release); err != nil {
|
||||
return nil, fmt.Errorf("failed to parse release info: %w", err)
|
||||
}
|
||||
return &release, nil
|
||||
}
|
||||
|
||||
// buildAssetName constructs the expected asset filename for the current platform
|
||||
func buildAssetName(version string) string {
|
||||
goos := runtime.GOOS
|
||||
goarch := runtime.GOARCH
|
||||
|
||||
// normalize arch names
|
||||
if goarch == "amd64" {
|
||||
goarch = "amd64"
|
||||
} else if goarch == "arm64" {
|
||||
goarch = "arm64"
|
||||
}
|
||||
|
||||
return fmt.Sprintf("yao-%s-%s-%s", version, goos, goarch)
|
||||
}
|
||||
|
||||
// findAsset finds the matching asset by name prefix
|
||||
func findAsset(assets []githubAsset, name string) *githubAsset {
|
||||
for i, a := range assets {
|
||||
if a.Name == name {
|
||||
return &assets[i]
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// downloadAndReplace downloads the new binary and replaces the current executable
|
||||
func downloadAndReplace(url, exePath string) error {
|
||||
client := &http.Client{Timeout: 10 * time.Minute}
|
||||
resp, err := client.Get(url)
|
||||
if err != nil {
|
||||
return fmt.Errorf("download failed: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return fmt.Errorf("download failed with status %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
// write to a temp file in the same directory as the executable
|
||||
dir := filepath.Dir(exePath)
|
||||
tmpFile, err := os.CreateTemp(dir, ".yao-upgrade-*")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create temp file: %w", err)
|
||||
}
|
||||
tmpPath := tmpFile.Name()
|
||||
defer func() {
|
||||
tmpFile.Close()
|
||||
os.Remove(tmpPath)
|
||||
}()
|
||||
|
||||
total := resp.ContentLength
|
||||
var downloaded int64
|
||||
buf := make([]byte, 32*1024)
|
||||
lastPrint := time.Now()
|
||||
|
||||
for {
|
||||
n, err := resp.Body.Read(buf)
|
||||
if n > 0 {
|
||||
if _, werr := tmpFile.Write(buf[:n]); werr != nil {
|
||||
return fmt.Errorf("write failed: %w", werr)
|
||||
}
|
||||
downloaded += int64(n)
|
||||
if time.Since(lastPrint) > 500*time.Millisecond || err == io.EOF {
|
||||
if total > 0 {
|
||||
pct := float64(downloaded) / float64(total) * 100
|
||||
fmt.Printf("\r %s %.1f%% (%d / %d MB)",
|
||||
color.CyanString(L("Progress:")),
|
||||
pct,
|
||||
downloaded/1024/1024,
|
||||
total/1024/1024,
|
||||
)
|
||||
} else {
|
||||
fmt.Printf("\r %s %d MB downloaded", color.CyanString(L("Progress:")), downloaded/1024/1024)
|
||||
}
|
||||
lastPrint = time.Now()
|
||||
}
|
||||
}
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("download interrupted: %w", err)
|
||||
}
|
||||
}
|
||||
fmt.Println()
|
||||
|
||||
if err := tmpFile.Close(); err != nil {
|
||||
return fmt.Errorf("failed to close temp file: %w", err)
|
||||
}
|
||||
|
||||
// make executable
|
||||
if err := os.Chmod(tmpPath, 0755); err != nil {
|
||||
return fmt.Errorf("failed to chmod: %w", err)
|
||||
}
|
||||
|
||||
// atomically replace the executable
|
||||
if err := os.Rename(tmpPath, exePath); err != nil {
|
||||
// on some systems (cross-device) rename fails, fall back to copy
|
||||
if err2 := copyFile(tmpPath, exePath); err2 != nil {
|
||||
return fmt.Errorf("replace failed: %w (copy fallback: %v)", err, err2)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// copyFile copies src to dst, used as fallback when rename fails cross-device
|
||||
func copyFile(src, dst string) error {
|
||||
in, err := os.Open(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer in.Close()
|
||||
|
||||
out, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0755)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer out.Close()
|
||||
|
||||
_, err = io.Copy(out, in)
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,14 +34,53 @@ func (w *sandboxWatcher) Check(ctx context.Context) []monitor.Alert {
|
|||
Target: "box:" + b.id,
|
||||
Message: fmt.Sprintf("status %s → %s", old, status),
|
||||
})
|
||||
if status == "running" && old != "running" {
|
||||
b.touch()
|
||||
alerts = append(alerts, monitor.Alert{
|
||||
Level: monitor.Trace,
|
||||
Target: "box:" + b.id,
|
||||
Message: fmt.Sprintf("touch on resume, lastCall reset to %s",
|
||||
time.UnixMilli(b.lastCall.Load()).Format(time.RFC3339)),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if status != "running" {
|
||||
return true
|
||||
}
|
||||
|
||||
// maxLifetime: independent of idle — prevents indefinitely running containers
|
||||
if b.policy == LongRunning {
|
||||
if lifetime := b.maxLifetime(); lifetime > 0 {
|
||||
age := time.Since(b.createdAt)
|
||||
if age > lifetime {
|
||||
alerts = append(alerts, monitor.Alert{
|
||||
Level: monitor.Warn,
|
||||
Target: "box:" + b.id,
|
||||
Message: fmt.Sprintf("lifetime expired (%s), removing", lifetime),
|
||||
Action: func(ctx context.Context) { mgr.Remove(ctx, b.id) },
|
||||
})
|
||||
} else {
|
||||
alerts = append(alerts, monitor.Alert{
|
||||
Level: monitor.Trace,
|
||||
Target: "box:" + b.id,
|
||||
Message: fmt.Sprintf("lifetime remaining %s (max=%s)",
|
||||
(lifetime - age).Round(time.Second), lifetime),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
idle := time.Since(b.idleSince())
|
||||
timeout := b.idleTimeout()
|
||||
|
||||
alerts = append(alerts, monitor.Alert{
|
||||
Level: monitor.Trace,
|
||||
Target: "box:" + b.id,
|
||||
Message: fmt.Sprintf("heartbeat status=%s policy=%s idle=%s timeout=%s",
|
||||
status, b.policy, idle.Round(time.Second), timeout),
|
||||
})
|
||||
|
||||
if timeout <= 0 || idle <= timeout {
|
||||
return true
|
||||
}
|
||||
|
|
@ -68,19 +107,6 @@ func (w *sandboxWatcher) Check(ctx context.Context) []monitor.Alert {
|
|||
})
|
||||
}
|
||||
|
||||
if b.policy == LongRunning {
|
||||
if lifetime := b.maxLifetime(); lifetime > 0 && time.Since(b.createdAt) > lifetime {
|
||||
alerts = append(alerts, monitor.Alert{
|
||||
Level: monitor.Warn,
|
||||
Target: "box:" + b.id,
|
||||
Message: fmt.Sprintf("lifetime expired (%s), removing", lifetime),
|
||||
Action: func(ctx context.Context) {
|
||||
mgr.Remove(ctx, b.id)
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
})
|
||||
return alerts
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue