mirror of
https://github.com/memohai/Memoh.git
synced 2026-04-27 07:16:19 +09:00
fix(deploy): many docker compose bug
This commit is contained in:
@@ -9,7 +9,6 @@ import (
|
||||
"io"
|
||||
"log/slog"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"syscall"
|
||||
@@ -673,15 +672,8 @@ func (s *DefaultService) ExecTaskStreaming(ctx context.Context, containerID stri
|
||||
if req.Terminal {
|
||||
ioOpts = append(ioOpts, cio.WithTerminal)
|
||||
}
|
||||
fifoDir := strings.TrimSpace(req.FIFODir)
|
||||
if fifoDir == "" {
|
||||
if homeDir, err := os.UserHomeDir(); err == nil && homeDir != "" {
|
||||
fifoDir = filepath.Join(homeDir, ".memoh", "containerd-fifo")
|
||||
} else {
|
||||
fifoDir = "/tmp/memoh-containerd-fifo"
|
||||
}
|
||||
}
|
||||
if err := os.MkdirAll(fifoDir, 0o755); err != nil {
|
||||
fifoDir, err := resolveExecFIFODir(req.FIFODir)
|
||||
if err != nil {
|
||||
_ = stdinR.Close()
|
||||
_ = stdinW.Close()
|
||||
_ = stdoutR.Close()
|
||||
@@ -752,6 +744,27 @@ func (s *DefaultService) ExecTaskStreaming(ctx context.Context, containerID stri
|
||||
}, nil
|
||||
}
|
||||
|
||||
func resolveExecFIFODir(preferred string) (string, error) {
|
||||
candidates := make([]string, 0, 3)
|
||||
if p := strings.TrimSpace(preferred); p != "" {
|
||||
candidates = append(candidates, p)
|
||||
}
|
||||
candidates = append(candidates, "/var/lib/containerd/memoh-fifo", "/tmp/memoh-containerd-fifo")
|
||||
|
||||
var lastErr error
|
||||
for _, dir := range candidates {
|
||||
if err := os.MkdirAll(dir, 0o755); err == nil {
|
||||
return dir, nil
|
||||
} else {
|
||||
lastErr = err
|
||||
}
|
||||
}
|
||||
if lastErr == nil {
|
||||
lastErr = fmt.Errorf("no fifo directory candidate available")
|
||||
}
|
||||
return "", lastErr
|
||||
}
|
||||
|
||||
func (s *DefaultService) ListContainersByLabel(ctx context.Context, key, value string) ([]containerd.Container, error) {
|
||||
if key == "" {
|
||||
return nil, ErrInvalidArgument
|
||||
|
||||
+37
-5
@@ -4,11 +4,13 @@ import (
|
||||
"bufio"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
@@ -188,7 +190,8 @@ func (h *ContainerdHandler) getMCPSession(ctx context.Context, containerID strin
|
||||
|
||||
func (h *ContainerdHandler) startContainerdMCPSession(ctx context.Context, containerID string) (*mcpSession, error) {
|
||||
execSession, err := h.service.ExecTaskStreaming(ctx, containerID, ctr.ExecTaskRequest{
|
||||
Args: []string{"/app/mcp"},
|
||||
Args: []string{"/app/mcp"},
|
||||
FIFODir: h.mcpFIFODir(),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -207,11 +210,15 @@ func (h *ContainerdHandler) startContainerdMCPSession(ctx context.Context, conta
|
||||
go func() {
|
||||
_, err := execSession.Wait()
|
||||
if err != nil {
|
||||
if isBenignMCPSessionExit(err) {
|
||||
sess.closeWithError(io.EOF)
|
||||
return
|
||||
}
|
||||
h.logger.Error("mcp session exited", slog.Any("error", err), slog.String("container_id", containerID))
|
||||
sess.closeWithError(err)
|
||||
} else {
|
||||
sess.closeWithError(io.EOF)
|
||||
return
|
||||
}
|
||||
sess.closeWithError(io.EOF)
|
||||
}()
|
||||
|
||||
return sess, nil
|
||||
@@ -273,11 +280,15 @@ func (h *ContainerdHandler) startLimaMCPSession(containerID string) (*mcpSession
|
||||
go sess.readLoop()
|
||||
go func() {
|
||||
if err := cmd.Wait(); err != nil {
|
||||
if isBenignMCPSessionExit(err) {
|
||||
sess.closeWithError(io.EOF)
|
||||
return
|
||||
}
|
||||
h.logger.Error("mcp session exited", slog.Any("error", err), slog.String("container_id", containerID))
|
||||
sess.closeWithError(err)
|
||||
} else {
|
||||
sess.closeWithError(io.EOF)
|
||||
return
|
||||
}
|
||||
sess.closeWithError(io.EOF)
|
||||
}()
|
||||
|
||||
return sess, nil
|
||||
@@ -320,11 +331,32 @@ func (h *ContainerdHandler) startMCPStderrLogger(stderr io.ReadCloser, container
|
||||
h.logger.Warn("mcp stderr", slog.String("container_id", containerID), slog.String("message", line))
|
||||
}
|
||||
if err := scanner.Err(); err != nil {
|
||||
if errors.Is(err, io.EOF) || errors.Is(err, io.ErrClosedPipe) || strings.Contains(err.Error(), "closed pipe") {
|
||||
return
|
||||
}
|
||||
h.logger.Error("mcp stderr read failed", slog.Any("error", err), slog.String("container_id", containerID))
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func isBenignMCPSessionExit(err error) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
if errors.Is(err, context.Canceled) || errors.Is(err, io.EOF) || errors.Is(err, io.ErrClosedPipe) {
|
||||
return true
|
||||
}
|
||||
msg := strings.ToLower(err.Error())
|
||||
return strings.Contains(msg, "code = canceled") || strings.Contains(msg, "context canceled") || strings.Contains(msg, "closed pipe")
|
||||
}
|
||||
|
||||
func (h *ContainerdHandler) mcpFIFODir() string {
|
||||
if root := strings.TrimSpace(h.cfg.DataRoot); root != "" {
|
||||
return filepath.Join(root, ".containerd-fifo")
|
||||
}
|
||||
return "/tmp/memoh-containerd-fifo"
|
||||
}
|
||||
|
||||
func (s *mcpSession) readLoop() {
|
||||
scanner := bufio.NewScanner(s.stdout)
|
||||
scanner.Buffer(make([]byte, 0, 64*1024), 8*1024*1024)
|
||||
|
||||
@@ -178,6 +178,7 @@ func (h *ContainerdHandler) startContainerdMCPCommandSession(ctx context.Context
|
||||
Args: args,
|
||||
Env: env,
|
||||
WorkDir: strings.TrimSpace(req.Cwd),
|
||||
FIFODir: h.mcpFIFODir(),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -195,11 +196,15 @@ func (h *ContainerdHandler) startContainerdMCPCommandSession(ctx context.Context
|
||||
go func() {
|
||||
_, err := execSession.Wait()
|
||||
if err != nil {
|
||||
if isBenignMCPSessionExit(err) {
|
||||
sess.closeWithError(io.EOF)
|
||||
return
|
||||
}
|
||||
h.logger.Error("mcp stdio session exited", slog.Any("error", err), slog.String("container_id", containerID))
|
||||
sess.closeWithError(err)
|
||||
} else {
|
||||
sess.closeWithError(io.EOF)
|
||||
return
|
||||
}
|
||||
sess.closeWithError(io.EOF)
|
||||
}()
|
||||
return sess, nil
|
||||
}
|
||||
@@ -342,11 +347,15 @@ func (h *ContainerdHandler) startLimaMCPCommandSession(containerID string, req M
|
||||
go sess.readLoop()
|
||||
go func() {
|
||||
if err := cmd.Wait(); err != nil {
|
||||
if isBenignMCPSessionExit(err) {
|
||||
sess.closeWithError(io.EOF)
|
||||
return
|
||||
}
|
||||
h.logger.Error("mcp stdio session exited", slog.Any("error", err), slog.String("container_id", containerID))
|
||||
sess.closeWithError(err)
|
||||
} else {
|
||||
sess.closeWithError(io.EOF)
|
||||
return
|
||||
}
|
||||
sess.closeWithError(io.EOF)
|
||||
}()
|
||||
|
||||
return sess, nil
|
||||
|
||||
@@ -17,6 +17,7 @@ func NewPingHandler(log *slog.Logger) *PingHandler {
|
||||
|
||||
func (h *PingHandler) Register(e *echo.Echo) {
|
||||
e.GET("/ping", h.Ping)
|
||||
e.HEAD("/health", h.PingHead)
|
||||
}
|
||||
|
||||
func (h *PingHandler) Ping(c echo.Context) error {
|
||||
@@ -24,3 +25,7 @@ func (h *PingHandler) Ping(c echo.Context) error {
|
||||
"status": "ok",
|
||||
})
|
||||
}
|
||||
|
||||
func (h *PingHandler) PingHead(c echo.Context) error {
|
||||
return c.NoContent(http.StatusOK)
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ func NewServer(log *slog.Logger, addr string, jwtSecret string, pingHandler *han
|
||||
}))
|
||||
e.Use(auth.JWTMiddleware(jwtSecret, func(c echo.Context) bool {
|
||||
path := c.Request().URL.Path
|
||||
if path == "/ping" || path == "/api/swagger.json" || path == "/auth/login" {
|
||||
if path == "/ping" || path == "/health" || path == "/api/swagger.json" || path == "/auth/login" {
|
||||
return true
|
||||
}
|
||||
if strings.HasPrefix(path, "/api/docs") {
|
||||
|
||||
Reference in New Issue
Block a user