Add support for schedules (#137)
All checks were successful
Backend Build and Test / build (push) Successful in 3m42s
Backend Deploy / build (push) Successful in 4m46s

Reviewed-on: #137
This commit was merged in pull request #137.
This commit is contained in:
2025-05-30 20:22:33 +02:00
parent 5a20e76df2
commit 06c8ebcbcc
11 changed files with 199 additions and 23 deletions

View File

@@ -3,6 +3,7 @@ package main
import (
"errors"
"fmt"
"github.com/adhocore/gronx"
"log"
"math"
"time"
@@ -313,10 +314,20 @@ func (db *Db) CreateTask(task *CreateTaskRequest) (int, error) {
}
defer tx.MustRollback()
var nextRun *int64
if task.Schedule != nil {
nextRunTime, err := gronx.NextTick(*task.Schedule, false)
if err != nil {
return 0, fmt.Errorf("failed to calculate next run: %w", err)
}
nextRunTimeAsInt := nextRunTime.Unix()
nextRun = &nextRunTimeAsInt
}
// Insert the new task
reward := int(math.Round(task.Reward * 100.0))
err = tx.Query("insert into tasks (name, reward, assigned) values (?, ?, ?)").
Bind(task.Name, reward, task.Assigned).
err = tx.Query("insert into tasks (name, reward, assigned, schedule, next_run) values (?, ?, ?, ?, ?)").
Bind(task.Name, reward, task.Assigned, task.Schedule, nextRun).
Exec()
if err != nil {
@@ -340,13 +351,17 @@ func (db *Db) CreateTask(task *CreateTaskRequest) (int, error) {
}
func (db *Db) GetTasks() ([]Task, error) {
tasks := make([]Task, 0)
var err error
err := db.UpdateScheduledTasks()
if err != nil {
return nil, fmt.Errorf("failed to update scheduled tasks: %w", err)
}
for row := range db.db.Query("select id, name, reward, assigned from tasks").Range(&err) {
tasks := make([]Task, 0)
for row := range db.db.Query("select id, name, reward, assigned, schedule from tasks where completed is null").Range(&err) {
task := Task{}
var reward int64
err = row.Scan(&task.ID, &task.Name, &reward, &task.Assigned)
err = row.Scan(&task.ID, &task.Name, &reward, &task.Assigned, &task.Schedule)
task.Reward = float64(reward) / 100.0
if err != nil {
return nil, err
@@ -362,16 +377,78 @@ func (db *Db) GetTasks() ([]Task, error) {
func (db *Db) GetTask(id int) (Task, error) {
task := Task{}
var reward int64
err := db.db.Query("select id, name, reward, assigned from tasks where id = ?").
Bind(id).ScanSingle(&task.ID, &task.Name, &reward, &task.Assigned)
task.Reward = float64(reward) / 100.0
err := db.UpdateScheduledTasks()
if err != nil {
return Task{}, err
return Task{}, fmt.Errorf("failed to update scheduled tasks: %w", err)
}
var reward int64
err = db.db.Query("select id, name, reward, assigned, schedule from tasks where id = ? and completed is null").
Bind(id).ScanSingle(&task.ID, &task.Name, &reward, &task.Assigned, &task.Schedule)
if err != nil {
return task, err
}
task.Reward = float64(reward) / 100.0
return task, nil
}
func (db *Db) UpdateScheduledTasks() error {
type ScheduledTask struct {
ID int
Schedule string
Expires int64
}
tasks := make([]ScheduledTask, 0)
var err error
for row := range db.db.Query("select id, schedule, next_run from tasks where schedule is not null").Range(&err) {
task := ScheduledTask{}
err := row.Scan(&task.ID, &task.Schedule, &task.Expires)
if err != nil {
return err
}
if time.Now().Unix() >= task.Expires {
tasks = append(tasks, task)
}
}
if err != nil {
return fmt.Errorf("failed to fetch scheduled tasks: %w", err)
}
tx, err := db.db.Begin()
if err != nil {
return err
}
defer tx.MustRollback()
for _, task := range tasks {
nextRun, err := gronx.NextTickAfter(task.Schedule, time.Now(), false)
if err != nil {
return fmt.Errorf("failed to calculate next run for task %d: %w", task.ID, err)
}
err = tx.Query("insert into tasks (name, reward, assigned, schedule, next_run) select name, reward, assigned, schedule, ? from tasks where id = ?").
Bind(nextRun.Unix(), task.ID).
Exec()
if err != nil {
return err
}
err = tx.Query("update tasks set schedule = null where id = ?").Bind(task.ID).Exec()
if err != nil {
return err
}
tx.Query("select last_insert_rowid()").MustScanSingle(&task.ID)
log.Printf("Task %d scheduled for %s", task.ID, nextRun)
}
if err != nil {
return err
}
return tx.Commit()
}
func (db *Db) DeleteTask(id int) error {
tx, err := db.db.Begin()
if err != nil {
@@ -453,7 +530,10 @@ func (db *Db) CompleteTask(taskId int) error {
}
// Remove the task
err = tx.Query("delete from tasks where id = ?").Bind(taskId).Exec()
err = tx.Query("update tasks set completed=? where id = ?").Bind(time.Now().Unix(), taskId).Exec()
if err != nil {
return err
}
return tx.Commit()
}