fix: kill rclone subprocess on reader close

Prevent cat processes from hanging after the pipe is closed.
This commit is contained in:
krau
2026-08-16 20:28:15 +08:00
parent bd7da7c31e
commit d1b2dbfe5f
2 changed files with 10 additions and 17 deletions

View File

@@ -8,7 +8,4 @@ var (
ErrFailedToSaveFile = errors.New("rclone: failed to save file")
ErrFailedToListFiles = errors.New("rclone: failed to list files")
ErrFailedToOpenFile = errors.New("rclone: failed to open file")
ErrFailedToCheckFile = errors.New("rclone: failed to check file exists")
ErrFailedToCreateDir = errors.New("rclone: failed to create directory")
ErrCommandFailed = errors.New("rclone: command execution failed")
)

View File

@@ -13,11 +13,11 @@ import (
"time"
"github.com/charmbracelet/log"
"github.com/krau/SaveAny-Bot/common/utils/fsutil"
config "github.com/krau/SaveAny-Bot/config/storage"
"github.com/krau/SaveAny-Bot/pkg/enums/ctxkey"
storenum "github.com/krau/SaveAny-Bot/pkg/enums/storage"
"github.com/krau/SaveAny-Bot/pkg/storagetypes"
"github.com/rs/xid"
)
type Rclone struct {
@@ -51,9 +51,6 @@ func (r *Rclone) Init(ctx context.Context, cfg config.StorageConfig) error {
}
remoteName := strings.TrimSuffix(r.config.Remote, ":")
if !strings.HasSuffix(r.config.Remote, ":") {
remoteName = r.config.Remote
}
found := false
scanner := bufio.NewScanner(bytes.NewReader(output))
@@ -105,18 +102,11 @@ func (r *Rclone) getRemotePath(storagePath string) string {
func (r *Rclone) Save(ctx context.Context, reader io.Reader, storagePath string) error {
r.logger.Infof("Saving file to %s", storagePath)
ext := path.Ext(storagePath)
base := strings.TrimSuffix(storagePath, ext)
candidate := storagePath
if overwrite, _ := ctx.Value(ctxkey.OverwriteExisting).(bool); !overwrite {
for i := 1; r.Exists(ctx, candidate); i++ {
candidate = fmt.Sprintf("%s_%d%s", base, i, ext)
if i > 100 {
r.logger.Errorf("Too many attempts to find a unique filename for %s", storagePath)
candidate = fmt.Sprintf("%s_%s%s", base, xid.New().String(), ext)
break
}
}
candidate = fsutil.UniquePath("", storagePath, func(c string) bool {
return r.Exists(ctx, c)
}, 100)
}
remotePath := r.getRemotePath(candidate)
@@ -285,6 +275,12 @@ func (r *rcloneCatReader) Close() error {
if err := r.reader.Close(); err != nil {
r.logger.Warnf("Failed to close reader: %v", err)
}
// 主动杀掉子进程, 防止 rclone cat 在管道关闭后仍挂起导致 Wait 永久阻塞
if r.cmd.Process != nil {
if err := r.cmd.Process.Kill(); err != nil {
r.logger.Warnf("Failed to kill rclone cat process: %v", err)
}
}
if err := r.cmd.Wait(); err != nil {
r.logger.Warnf("rclone cat process exited with error: %v", err)
}