mirror of
https://github.com/krau/SaveAny-Bot.git
synced 2026-08-29 20:26:42 +08:00
feat(core): persist tasks and recover them after restart
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"time"
|
||||
)
|
||||
|
||||
var errNotInitialized = errors.New("database not initialized")
|
||||
|
||||
type TaskStatus string
|
||||
|
||||
const (
|
||||
TaskStatusQueued TaskStatus = "queued"
|
||||
TaskStatusRunning TaskStatus = "running"
|
||||
TaskStatusFailed TaskStatus = "failed"
|
||||
TaskStatusCancelled TaskStatus = "cancelled"
|
||||
)
|
||||
|
||||
// Task is the persisted record of a queued or running task, used to recover
|
||||
// unfinished work after a process restart. Completed tasks are deleted on
|
||||
// finish, so the table only ever holds queued/running rows.
|
||||
type Task struct {
|
||||
ID string `gorm:"primaryKey;size:64"`
|
||||
Type string `gorm:"size:32;index"`
|
||||
Payload []byte
|
||||
Status string `gorm:"size:16;index"`
|
||||
Error string
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
|
||||
func CreateTask(ctx context.Context, task *Task) error {
|
||||
if db == nil {
|
||||
return errNotInitialized
|
||||
}
|
||||
return db.WithContext(ctx).Create(task).Error
|
||||
}
|
||||
|
||||
// UpsertTask inserts the task or replaces the existing row with the same ID.
|
||||
func UpsertTask(ctx context.Context, task *Task) error {
|
||||
if db == nil {
|
||||
return errNotInitialized
|
||||
}
|
||||
return db.WithContext(ctx).Save(task).Error
|
||||
}
|
||||
|
||||
func UpdateTaskStatus(ctx context.Context, id string, status TaskStatus, errMsg string) error {
|
||||
if db == nil {
|
||||
return errNotInitialized
|
||||
}
|
||||
return db.WithContext(ctx).Model(&Task{}).
|
||||
Where("id = ?", id).
|
||||
Updates(map[string]any{
|
||||
"status": status,
|
||||
"error": errMsg,
|
||||
"updated_at": time.Now(),
|
||||
}).Error
|
||||
}
|
||||
|
||||
func DeleteTask(ctx context.Context, id string) error {
|
||||
if db == nil {
|
||||
return errNotInitialized
|
||||
}
|
||||
return db.WithContext(ctx).Delete(&Task{}, "id = ?", id).Error
|
||||
}
|
||||
|
||||
// GetUnfinishedTasks returns all tasks that were not finished when the
|
||||
// process stopped, i.e. tasks that must be re-enqueued on startup.
|
||||
func GetUnfinishedTasks(ctx context.Context) ([]Task, error) {
|
||||
if db == nil {
|
||||
return nil, errNotInitialized
|
||||
}
|
||||
var tasks []Task
|
||||
err := db.WithContext(ctx).
|
||||
Where("status IN ?", []string{string(TaskStatusQueued), string(TaskStatusRunning)}).
|
||||
Order("created_at").
|
||||
Find(&tasks).Error
|
||||
return tasks, err
|
||||
}
|
||||
|
||||
func CountUnfinishedTasks(ctx context.Context) (int64, error) {
|
||||
if db == nil {
|
||||
return 0, errNotInitialized
|
||||
}
|
||||
var count int64
|
||||
err := db.WithContext(ctx).
|
||||
Model(&Task{}).
|
||||
Where("status IN ?", []string{string(TaskStatusQueued), string(TaskStatusRunning)}).
|
||||
Count(&count).Error
|
||||
return count, err
|
||||
}
|
||||
Reference in New Issue
Block a user