feat: cron arithmetic and persisted workflow schedules
This commit is contained in:
@@ -8,6 +8,7 @@ import (
|
||||
|
||||
"gitea.hostxtra.co.uk/mrhid6/vantage/server/internal/db"
|
||||
"gitea.hostxtra.co.uk/mrhid6/vantage/server/internal/models"
|
||||
"gitea.hostxtra.co.uk/mrhid6/vantage/server/internal/workflowsched"
|
||||
"github.com/google/uuid"
|
||||
"go.mongodb.org/mongo-driver/v2/bson"
|
||||
"go.mongodb.org/mongo-driver/v2/mongo"
|
||||
@@ -60,6 +61,11 @@ func EnsureWorkflowIndexes() error {
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := db.Col("workflows").Indexes().CreateOne(ctx, mongo.IndexModel{
|
||||
Keys: bson.D{{Key: "next_run_at", Value: 1}},
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := EnsureLogIndexes(); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -321,3 +327,45 @@ func DeleteWorkflow(instanceID, id string) error {
|
||||
_, err := db.Col("workflows").DeleteOne(ctx, bson.M{"workflow_id": id, "instance_id": instanceID})
|
||||
return err
|
||||
}
|
||||
|
||||
// SetSchedule validates and stores a workflow's schedule, computing the first
|
||||
// occurrence. next_run_at is persisted rather than held in memory: a leader
|
||||
// handover between computing an occurrence and firing it would otherwise lose
|
||||
// it or fire it twice.
|
||||
//
|
||||
// Passing s == nil, or a disabled schedule, clears next_run_at so the
|
||||
// scheduler's query stops matching the document at all.
|
||||
func SetSchedule(instanceID, workflowID string, s *models.Schedule) (*time.Time, error) {
|
||||
ctx, cancel := wfCtx()
|
||||
defer cancel()
|
||||
|
||||
set := bson.M{"schedule": s, "updated_at": time.Now()}
|
||||
unset := bson.M{}
|
||||
|
||||
var next *time.Time
|
||||
if s != nil && s.Enabled {
|
||||
at, err := workflowsched.NextOccurrence(s.Cron, s.TZ, time.Now())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
next = &at
|
||||
set["next_run_at"] = at
|
||||
} else {
|
||||
unset["next_run_at"] = ""
|
||||
}
|
||||
|
||||
update := bson.M{"$set": set}
|
||||
if len(unset) > 0 {
|
||||
update["$unset"] = unset
|
||||
}
|
||||
|
||||
res, err := db.Col("workflows").UpdateOne(ctx,
|
||||
bson.M{"workflow_id": workflowID, "instance_id": instanceID}, update)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if res.MatchedCount == 0 {
|
||||
return nil, mongo.ErrNoDocuments
|
||||
}
|
||||
return next, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user