Немного увеличена стабильность работы, а также добавлены логи
This commit is contained in:
@@ -6,13 +6,37 @@ import (
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"gitea.unprism.ru/KRBL/Agate/models"
|
||||
"gitea.unprism.ru/KRBL/Agate/store"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
const blobExtension = ".zip"
|
||||
|
||||
// progressReader — обертка для логирования
|
||||
type progressReader struct {
|
||||
reader io.Reader
|
||||
totalRead int64
|
||||
lastLog time.Time
|
||||
snapshotID string
|
||||
}
|
||||
|
||||
func (pr *progressReader) Read(p []byte) (int, error) {
|
||||
n, err := pr.reader.Read(p)
|
||||
pr.totalRead += int64(n)
|
||||
|
||||
// Логируем каждые 5 секунд
|
||||
if time.Since(pr.lastLog) > 5*time.Second {
|
||||
log.Printf("Snapshot %s download progress: %.2f MB downloaded",
|
||||
pr.snapshotID, float64(pr.totalRead)/1024/1024)
|
||||
pr.lastLog = time.Now()
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
|
||||
// fileSystemStore реализует интерфейс store.BlobStore с использованием локальной файловой системы.
|
||||
type fileSystemStore struct {
|
||||
baseDir string // Директория для хранения блобов (архивов)
|
||||
@@ -47,23 +71,49 @@ func (fs *fileSystemStore) getBlobPath(snapshotID string) string {
|
||||
// StoreBlob сохраняет данные из reader в файл в baseDir.
|
||||
func (fs *fileSystemStore) StoreBlob(ctx context.Context, snapshotID string, reader io.Reader) (string, error) {
|
||||
blobPath := fs.getBlobPath(snapshotID)
|
||||
log.Printf("Starting to store blob for snapshot %s at %s", snapshotID, blobPath)
|
||||
|
||||
// Создаем или перезаписываем файл
|
||||
file, err := os.Create(blobPath)
|
||||
// Используем временный файл, чтобы не повредить (возможно) существующий валидный файл
|
||||
// если загрузка упадет на середине.
|
||||
tempPath := blobPath + ".tmp"
|
||||
file, err := os.Create(tempPath)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to create blob file %s: %w", blobPath, err)
|
||||
return "", fmt.Errorf("failed to create temp blob file %s: %w", tempPath, err)
|
||||
}
|
||||
defer file.Close() // Гарантируем закрытие файла
|
||||
defer file.Close()
|
||||
|
||||
// Копируем данные из ридера в файл
|
||||
_, err = io.Copy(file, reader)
|
||||
if err != nil {
|
||||
// Если произошла ошибка копирования, удаляем неполный файл
|
||||
os.Remove(blobPath)
|
||||
return "", fmt.Errorf("failed to write data to blob file %s: %w", blobPath, err)
|
||||
// Оборачиваем reader для логирования
|
||||
pr := &progressReader{
|
||||
reader: reader,
|
||||
snapshotID: snapshotID,
|
||||
lastLog: time.Now(),
|
||||
}
|
||||
|
||||
// Возвращаем путь к созданному файлу
|
||||
// Копируем данные
|
||||
written, err := io.Copy(file, pr)
|
||||
if err != nil {
|
||||
file.Close()
|
||||
os.Remove(tempPath) // Удаляем мусор
|
||||
return "", fmt.Errorf("failed to write data to blob file %s: %w", tempPath, err)
|
||||
}
|
||||
|
||||
// Важный момент: Sync, чтобы убедиться, что данные на диске
|
||||
if err := file.Sync(); err != nil {
|
||||
file.Close()
|
||||
os.Remove(tempPath)
|
||||
return "", fmt.Errorf("failed to sync file to disk: %w", err)
|
||||
}
|
||||
|
||||
file.Close() // Закрываем перед переименованием
|
||||
|
||||
// Переименовываем временный файл в финальный (атомарная операция)
|
||||
if err := os.Rename(tempPath, blobPath); err != nil {
|
||||
return "", fmt.Errorf("failed to rename temp file to final blob: %w", err)
|
||||
}
|
||||
|
||||
log.Printf("Successfully stored blob for snapshot %s. Total size: %.2f MB",
|
||||
snapshotID, float64(written)/1024/1024)
|
||||
|
||||
return blobPath, nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user