// Copyright (c) 2025 Zeni Kim // Use of this source code is governed by MIT-style // license that can be found in the LICENSE file. package controllers import ( "context" "encoding/json" "fmt" "git.smarteching.com/goffee/core" ) // SchedulerSample demonstrates enqueuing tasks into the simple scheduler // from a controller. func SchedulerSample(c *core.Context) *core.Response { store := core.ResolveSchedulerStore() if store == nil { return c.Response.SetStatusCode(500).Json(`{"message": "scheduler store not available"}`) } ctx := context.Background() // ── Enqueue a "send_email" task (runs once, sequential) ──────────────── emailPayload, _ := json.Marshal(map[string]interface{}{ "to": "user@example.com", "subject": "Hello from the scheduler!", }) item1, err := store.Enqueue(ctx, "send_email", string(emailPayload), 0, 1, 0) if err != nil { c.GetLogger().Error(fmt.Sprintf("failed to enqueue send_email: %v", err)) return c.Response.SetStatusCode(500).Json(`{"message": "failed to enqueue send_email"}`) } c.GetLogger().Info(fmt.Sprintf("[scheduler] enqueued send_email task id=%d (maxRuns=1, thread=0)", item1.ID)) // ── Enqueue a "flaky_task" (runs 3 times, sequential) ────────────────── flakyPayload, _ := json.Marshal(map[string]interface{}{ "description": "This task will fail and the error will be recorded", }) item2, err := store.Enqueue(ctx, "flaky_task", string(flakyPayload), 0, 3, 0) if err != nil { c.GetLogger().Error(fmt.Sprintf("failed to enqueue flaky_task: %v", err)) return c.Response.SetStatusCode(500).Json(`{"message": "failed to enqueue flaky_task"}`) } c.GetLogger().Info(fmt.Sprintf("[scheduler] enqueued flaky_task id=%d (maxRuns=3, thread=0)", item2.ID)) // ── Enqueue a high-priority "send_email" (repeats indefinitely, concurrent) ── urgentPayload, _ := json.Marshal(map[string]interface{}{ "to": "urgent@example.com", "subject": "URGENT: Priority message", }) item3, err := store.Enqueue(ctx, "send_email", string(urgentPayload), 10, -1, 1) if err != nil { c.GetLogger().Error(fmt.Sprintf("failed to enqueue urgent send_email: %v", err)) return c.Response.SetStatusCode(500).Json(`{"message": "failed to enqueue urgent send_email"}`) } c.GetLogger().Info(fmt.Sprintf("[scheduler] enqueued high-priority send_email id=%d (maxRuns=-1/infinite, thread=1/concurrent)", item3.ID)) message := fmt.Sprintf(`{"message": "Enqueued 3 scheduler tasks (send_email x2, flaky_task x1)", "tasks": [%d, %d, %d]}`, item1.ID, item2.ID, item3.ID) return c.Response.Json(message) } // SchedulerSemaphoreToggle flips the scheduler semaphore state. // If it was green it becomes red (blocking execution), and vice versa. // Useful for testing the semaphore kill switch without restarting the app. func SchedulerSemaphoreToggle(c *core.Context) *core.Response { wasGreen := core.SchedulerSemaphoreIsGreen() if wasGreen { core.SchedulerSemaphoreSetRed() } else { core.SchedulerSemaphoreSetGreen() } newState := "GREEN" if !core.SchedulerSemaphoreIsGreen() { newState = "RED" } c.GetLogger().Info(fmt.Sprintf("[scheduler] semaphore toggled: was %s → now %s", map[bool]string{true: "GREEN", false: "RED"}[wasGreen], newState)) message := fmt.Sprintf(`{"message": "Scheduler semaphore flipped", "was": "%s", "now": "%s"}`, map[bool]string{true: "GREEN", false: "RED"}[wasGreen], newState) return c.Response.Json(message) }