Changeset 0.28.0.2 (#174)
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
// v0.27.1: Foundation — scheduler loop + service channel creation.
|
||||
// v0.27.2: Adds global config checks (enabled, max_concurrent), full cron
|
||||
// parsing via robfig/cron/v3, and completion invocation via executor.
|
||||
// v0.28.0: Adopt queued runs (webhook triggers), action tasks, C3/C4 audit fixes.
|
||||
package scheduler
|
||||
|
||||
import (
|
||||
@@ -104,18 +105,31 @@ func (s *Scheduler) execute(parentCtx context.Context, task models.Task) {
|
||||
return
|
||||
}
|
||||
|
||||
// v0.28.0: Check for queued run (from webhook trigger) — adopt it instead
|
||||
// of creating a new one so the trigger_payload is preserved.
|
||||
run, _ := s.stores.Tasks.GetQueuedRun(ctx, task.ID)
|
||||
if run != nil {
|
||||
// Adopt: transition queued → running
|
||||
_ = s.stores.Tasks.TransitionRunStatus(ctx, run.ID, "running")
|
||||
run.Status = "running"
|
||||
log.Printf("[scheduler] Adopting queued run %s for task %s (%s)", run.ID, task.ID, task.Name)
|
||||
} else {
|
||||
// Normal cron-triggered execution — create a new run
|
||||
run = &models.TaskRun{
|
||||
TaskID: task.ID,
|
||||
Status: "running",
|
||||
}
|
||||
if err := s.stores.Tasks.CreateRun(ctx, run); err != nil {
|
||||
log.Printf("[scheduler] Failed to create run for task %s: %v", task.ID, err)
|
||||
s.advanceNextRun(ctx, task)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
log.Printf("[scheduler] Executing task %s (%s) type=%s", task.ID, task.Name, task.TaskType)
|
||||
|
||||
// Create run record
|
||||
run := &models.TaskRun{
|
||||
TaskID: task.ID,
|
||||
Status: "running",
|
||||
}
|
||||
if err := s.stores.Tasks.CreateRun(ctx, run); err != nil {
|
||||
log.Printf("[scheduler] Failed to create run for task %s: %v", task.ID, err)
|
||||
s.advanceNextRun(ctx, task)
|
||||
return
|
||||
}
|
||||
// Mark execution start (C4 fix: SetLastRun is now separate from SetNextRun)
|
||||
_ = s.stores.Tasks.SetLastRun(ctx, task.ID)
|
||||
|
||||
// Create or reuse service channel
|
||||
channelID, err := s.ensureServiceChannel(ctx, task)
|
||||
@@ -126,20 +140,25 @@ func (s *Scheduler) execute(parentCtx context.Context, task models.Task) {
|
||||
return
|
||||
}
|
||||
|
||||
// Persist the user prompt as a message
|
||||
// Persist the user prompt as a message (prompt tasks only)
|
||||
if task.TaskType == "prompt" && task.UserPrompt != "" && s.stores.Messages != nil {
|
||||
content := task.UserPrompt
|
||||
// v0.28.0: Prepend trigger payload as context if present
|
||||
if run.TriggerPayload != "" {
|
||||
content = "[Webhook trigger data]\n```json\n" + run.TriggerPayload + "\n```\n\n[Task instructions]\n" + task.UserPrompt
|
||||
}
|
||||
_ = s.stores.Messages.Create(ctx, &models.Message{
|
||||
ChannelID: channelID,
|
||||
Role: "user",
|
||||
Content: task.UserPrompt,
|
||||
Content: content,
|
||||
})
|
||||
}
|
||||
|
||||
// v0.27.2: Invoke completion via executor
|
||||
if s.executor != nil && task.TaskType == "prompt" {
|
||||
if s.executor != nil {
|
||||
s.executor.Execute(ctx, task, run, channelID)
|
||||
} else {
|
||||
// No executor or non-prompt task type — mark completed (channel + prompt persisted)
|
||||
// No executor — mark completed (channel + prompt persisted)
|
||||
_ = s.stores.Tasks.UpdateRun(ctx, run.ID, "completed", 0, 0, 0, "")
|
||||
_ = s.stores.Tasks.IncrementRunCount(ctx, task.ID)
|
||||
}
|
||||
@@ -168,11 +187,11 @@ func (s *Scheduler) ensureServiceChannel(ctx context.Context, task models.Task)
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Update task to reference this channel for future runs
|
||||
// C3 fix: Persist output_channel_id on the task so future runs reuse this channel.
|
||||
channelID := ch.ID
|
||||
_ = s.stores.Tasks.Update(ctx, task.ID, models.TaskPatch{})
|
||||
// Direct update for output_channel_id (not in patch for simplicity)
|
||||
// The channel accumulates output over multiple runs.
|
||||
_ = s.stores.Tasks.Update(ctx, task.ID, models.TaskPatch{
|
||||
OutputChannelID: &channelID,
|
||||
})
|
||||
|
||||
return channelID, nil
|
||||
}
|
||||
@@ -187,6 +206,13 @@ func (s *Scheduler) advanceNextRun(ctx context.Context, task models.Task) {
|
||||
return
|
||||
}
|
||||
|
||||
if task.Schedule == "webhook" {
|
||||
// Webhook tasks have no cron schedule — clear next_run_at.
|
||||
// They only fire when triggered externally.
|
||||
_ = s.stores.Tasks.SetNextRun(ctx, task.ID, nil)
|
||||
return
|
||||
}
|
||||
|
||||
// v0.27.2: Full cron parsing via robfig/cron/v3 (replaces hand-rolled parser).
|
||||
next := taskutil.NextRunFromSchedule(task.Schedule, task.Timezone)
|
||||
if next == nil {
|
||||
|
||||
Reference in New Issue
Block a user