Compare commits
No commits in common. "37a491c6b9cfd02eac80218ee420c2f8592607e3" and "f4476d3e89207dae1581d36f31ac6d0f1efc90a9" have entirely different histories.
37a491c6b9
...
f4476d3e89
6 changed files with 0 additions and 203 deletions
|
|
@ -1,31 +0,0 @@
|
||||||
// Copyright (c) 2026 Jose Cely <me@jacs.guru>
|
|
||||||
// Use of this source code is governed by MIT-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package config
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"git.smarteching.com/goffee/core"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Retrieve the main config for the Simple Scheduler
|
|
||||||
func GetSchedulerConfig() core.SchedulerConfig {
|
|
||||||
//#####################################
|
|
||||||
//# Main configuration for ####
|
|
||||||
//# the Simple Scheduler (sche) ####
|
|
||||||
//#####################################
|
|
||||||
|
|
||||||
return core.SchedulerConfig{
|
|
||||||
// For enabling and disabling the simple scheduler system
|
|
||||||
// set to true to enable it, set to false to disable
|
|
||||||
EnableScheduler: false,
|
|
||||||
|
|
||||||
// How often the scheduler polls the database for new tasks
|
|
||||||
SchedulerInterval: 10 * time.Second,
|
|
||||||
|
|
||||||
// Max tasks to process per tick (0 = unlimited)
|
|
||||||
SchedulerRateLimit: 5,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,89 +0,0 @@
|
||||||
// Copyright (c) 2025 Zeni Kim <zenik@smarteching.com>
|
|
||||||
// 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 ─────────────────────────────────────────
|
|
||||||
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)
|
|
||||||
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", item1.ID))
|
|
||||||
|
|
||||||
// ── Enqueue a "flaky_task" (demonstrates error recording) ───────────────
|
|
||||||
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)
|
|
||||||
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", item2.ID))
|
|
||||||
|
|
||||||
// ── Enqueue a high-priority "send_email" task ───────────────────────────
|
|
||||||
urgentPayload, _ := json.Marshal(map[string]interface{}{
|
|
||||||
"to": "urgent@example.com",
|
|
||||||
"subject": "URGENT: Priority message",
|
|
||||||
})
|
|
||||||
item3, err := store.Enqueue(ctx, "send_email", string(urgentPayload), 10)
|
|
||||||
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 task id=%d", 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)
|
|
||||||
}
|
|
||||||
3
main.go
3
main.go
|
|
@ -65,9 +65,6 @@ func main() {
|
||||||
if config.GetQueueConfig().EnableQueue == true {
|
if config.GetQueueConfig().EnableQueue == true {
|
||||||
registerQueues()
|
registerQueues()
|
||||||
}
|
}
|
||||||
if config.GetSchedulerConfig().EnableScheduler == true {
|
|
||||||
registerScheduler()
|
|
||||||
}
|
|
||||||
if config.GetGormConfig().EnableGorm == true {
|
if config.GetGormConfig().EnableGorm == true {
|
||||||
RunAutoMigrations()
|
RunAutoMigrations()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,71 +0,0 @@
|
||||||
// Copyright (c) 2025 Zeni Kim <zenik@smarteching.com>
|
|
||||||
// Use of this source code is governed by MIT-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"git.smarteching.com/goffee/core"
|
|
||||||
"git.smarteching.com/goffee/core/scheduler"
|
|
||||||
"git.smarteching.com/goffee/cup/config"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ─── Scheduler task handlers ─────────────────────────────────────────────────
|
|
||||||
|
|
||||||
// handleSendEmail processes a send_email scheduler task.
|
|
||||||
func handleSendEmail(ctx context.Context, item *scheduler.QueueItem) error {
|
|
||||||
var payload struct {
|
|
||||||
To string `json:"to"`
|
|
||||||
Subject string `json:"subject"`
|
|
||||||
}
|
|
||||||
if err := json.Unmarshal([]byte(item.Payload), &payload); err != nil {
|
|
||||||
return fmt.Errorf("invalid send_email payload: %w", err)
|
|
||||||
}
|
|
||||||
log.Printf("[scheduler] [send_email] → to=%s subject=%q", payload.To, payload.Subject)
|
|
||||||
time.Sleep(50 * time.Millisecond) // simulate I/O
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// handleFlakyTask demonstrates a task that always fails.
|
|
||||||
func handleFlakyTask(ctx context.Context, item *scheduler.QueueItem) error {
|
|
||||||
log.Printf("[scheduler] [flaky_task] attempting... payload=%s", item.Payload)
|
|
||||||
time.Sleep(100 * time.Millisecond)
|
|
||||||
return fmt.Errorf("external API returned 503 — simulated failure for demo")
|
|
||||||
}
|
|
||||||
|
|
||||||
// ─── Registration ────────────────────────────────────────────────────────────
|
|
||||||
|
|
||||||
// Register simple scheduler
|
|
||||||
func registerScheduler() {
|
|
||||||
|
|
||||||
var sched = new(core.Schedulermux)
|
|
||||||
sched.SchedulerInit()
|
|
||||||
|
|
||||||
//########################################
|
|
||||||
//# scheduler task registration #####
|
|
||||||
//########################################
|
|
||||||
|
|
||||||
// Register your scheduler task handlers here ...
|
|
||||||
sched.AddWork("send_email", handleSendEmail)
|
|
||||||
sched.AddWork("flaky_task", handleFlakyTask)
|
|
||||||
|
|
||||||
//########################################
|
|
||||||
// Set the store (DB-backed) and start
|
|
||||||
//########################################
|
|
||||||
|
|
||||||
// Create the store using the application's GORM DB
|
|
||||||
st, err := scheduler.NewStore(core.ResolveGorm())
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf("scheduler: failed to create store: %v", err))
|
|
||||||
}
|
|
||||||
sched.SetStore(st)
|
|
||||||
|
|
||||||
// Start scheduler server in background, DO NOT TOUCH
|
|
||||||
go sched.RunScheduler(config.GetSchedulerConfig())
|
|
||||||
}
|
|
||||||
|
|
@ -31,10 +31,6 @@ func registerRoutes() {
|
||||||
// queue sample route
|
// queue sample route
|
||||||
controller.Get("/queuesample", controllers.Queuesample)
|
controller.Get("/queuesample", controllers.Queuesample)
|
||||||
|
|
||||||
// scheduler sample routes
|
|
||||||
controller.Get("/schedsample", controllers.SchedulerSample)
|
|
||||||
controller.Get("/schedsemaphore", controllers.SchedulerSemaphoreToggle)
|
|
||||||
|
|
||||||
// Uncomment the lines below to enable user administration
|
// Uncomment the lines below to enable user administration
|
||||||
controller.Get("/admin/users", controllers.AdminUsersList)
|
controller.Get("/admin/users", controllers.AdminUsersList)
|
||||||
controller.Post("/admin/users", controllers.AdminUsersList)
|
controller.Post("/admin/users", controllers.AdminUsersList)
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"git.smarteching.com/goffee/core"
|
"git.smarteching.com/goffee/core"
|
||||||
"git.smarteching.com/goffee/core/scheduler"
|
|
||||||
"git.smarteching.com/goffee/cup/models"
|
"git.smarteching.com/goffee/cup/models"
|
||||||
"git.smarteching.com/goffee/cup/utils"
|
"git.smarteching.com/goffee/cup/utils"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
|
|
@ -27,10 +26,6 @@ func RunAutoMigrations() {
|
||||||
db.AutoMigrate(&models.RolePermission{})
|
db.AutoMigrate(&models.RolePermission{})
|
||||||
db.AutoMigrate(&models.Permission{})
|
db.AutoMigrate(&models.Permission{})
|
||||||
|
|
||||||
// Simple scheduler (sche) tables — enabled when scheduler is active
|
|
||||||
db.AutoMigrate(&scheduler.QueueItem{})
|
|
||||||
db.AutoMigrate(&scheduler.ProcessedItem{})
|
|
||||||
|
|
||||||
// End your auto migrations
|
// End your auto migrations
|
||||||
|
|
||||||
// Create seed data data, DO NOT TOUCH
|
// Create seed data data, DO NOT TOUCH
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue