github.com/Laplace-Game-Development/Laplace-Entangled-Environment@v0.0.3/internal/schedule/schedule.go (about) 1 // The schedule package takes care of any "scheduled tasks". Using a combination of 2 // Cron and ZeroMQ, the schedule package distributes the consumption of tasks to 3 // multiple workers in order to speed up work as much as possible. 4 package schedule 5 6 import ( 7 "fmt" 8 "log" 9 10 "github.com/Laplace-Game-Development/Laplace-Entangled-Environment/internal/event" 11 "github.com/Laplace-Game-Development/Laplace-Entangled-Environment/internal/redis" 12 "github.com/mediocregopher/radix/v3" 13 "github.com/robfig/cron/v3" 14 ) 15 16 // A Cron Event represents a function that should be run 17 // at a certain schedule. This structure should be used 18 // when scheduling events at the onset of the application 19 type CronEvent struct { 20 Schedule string 21 Event func() 22 } 23 24 // Ledger of Cron Events 25 // This shouldn't be changed by the code. Used when initially scheduling 26 // functions to be run. 27 var initialCronLedger []CronEvent = []CronEvent{ 28 {"5 * * * * *", eventCheckHealth}, 29 } 30 31 //// Global Variables | Singletons 32 33 // Cron scheduling reference. This should only be used by this module. 34 // if you want to dynamically schedule (for whatever reason) use this 35 var mainCronInst *cron.Cron = nil 36 37 /////////////////////////////////////////////////////////////////////////////////////////////////// 38 //// 39 //// Scheduler Core Functionality 40 //// 41 /////////////////////////////////////////////////////////////////////////////////////////////////// 42 43 // ServerTask Startup Function for Cron Scheduling. Takes care of initialization. 44 func StartCronScheduler() (func(), error) { 45 err := initialSchedule() 46 if err != nil { 47 return nil, err 48 } 49 50 return cleanUpCronScheduler, nil 51 } 52 53 // CleanUp Function returned by Startup function. Stops all Cron scheduling and reports 54 // errors that occur when doing so. 55 func cleanUpCronScheduler() { 56 log.Println("Cleaning Cron Jobs!") 57 ctx := mainCronInst.Stop() 58 select { 59 case <-ctx.Done(): 60 log.Println(ctx.Err()) 61 default: 62 } 63 log.Println("Cron Jobs Clean!") 64 } 65 66 // Schedule Initialization called from StartCronScheduler. Goes through the 67 // "initialCronLedger" and adds each entry to the Cron scheduling reference. 68 // It also intitializes the Cron scheduling instance. 69 func initialSchedule() error { 70 mainCronInst = cron.New(cron.WithSeconds()) 71 72 for i, cronEvent := range initialCronLedger { 73 _, err := mainCronInst.AddFunc(cronEvent.Schedule, cronEvent.Event) 74 if err != nil { 75 log.Printf("Error Reached at Cron Event Index: %d\n", i) 76 return err 77 } 78 } 79 80 return nil 81 } 82 83 /////////////////////////////////////////////////////////////////////////////////////////////////// 84 //// 85 //// Schedule Events -- Cron Subscribed Functions 86 //// 87 /////////////////////////////////////////////////////////////////////////////////////////////////// 88 89 // Function added through the "initialCronLedger." Pops entries off of a list representing 90 // possibly old and unused games that need their data cleaned up. Send the data to Workers. 91 // See healthTaskWork to see how this data is used. 92 func eventCheckHealth() { 93 gameIDSlice := make([]string, EventHealthTaskCapacity) 94 gameIDSlicePrefixed := make([]string, EventHealthTaskCapacity) 95 96 err := redis.MainRedis.Do(radix.Cmd(&gameIDSlice, "LRANGE", event.HealthTaskQueue, "0", fmt.Sprintf("%d", EventHealthTaskCapacity-1))) 97 if err != nil { 98 log.Fatalln("Trouble Using Health Event: " + err.Error()) 99 } 100 101 err = redis.MainRedis.Do(radix.Cmd(nil, "LTRIM", event.HealthTaskQueue, fmt.Sprintf("%d", EventHealthTaskCapacity), "-1")) 102 if err != nil { 103 log.Fatalln("Trouble Using Health Event: " + err.Error()) 104 } 105 106 if len(gameIDSlice) == 0 { 107 return 108 } 109 110 for i, s := range gameIDSlice { 111 gameIDSlicePrefixed[i] = constructTaskWithPrefix(HealthTaskPrefix, s) 112 } 113 114 err = SendTasksToWorkers(gameIDSlicePrefixed...) 115 if err != nil { 116 log.Fatalf("Trouble Using Health Event! Error: %v", err.Error()) 117 } 118 }