github.com/ngicks/gokugen@v0.0.5/example/persistent_shceduler/main.go (about) 1 package main 2 3 import ( 4 "context" 5 "encoding/json" 6 "fmt" 7 "math/rand" 8 "os" 9 "path/filepath" 10 "time" 11 12 "github.com/ngicks/gokugen" 13 "github.com/ngicks/gokugen/impl/repository" 14 workregistry "github.com/ngicks/gokugen/impl/work_registry" 15 "github.com/ngicks/gokugen/scheduler" 16 taskstorage "github.com/ngicks/gokugen/task_storage" 17 syncparam "github.com/ngicks/type-param-common/sync-param" 18 ) 19 20 func main() { 21 if err := _main(); err != nil { 22 panic(err) 23 } 24 } 25 26 func printJsonIndent(j any) { 27 b, err := json.MarshalIndent(j, "", " ") 28 if err != nil { 29 panic(err) 30 } 31 fmt.Println(string(b)) 32 } 33 34 type Param1 struct { 35 Foo string 36 Bar string 37 } 38 39 func (p Param1) Mix() string { 40 var ret string 41 for range p.Foo { 42 for range p.Bar { 43 ret += string(p.Foo[rand.Int63n(int64(len(p.Foo)))]) 44 ret += string(p.Bar[rand.Int63n(int64(len(p.Bar)))]) 45 } 46 } 47 return ret 48 } 49 50 type Param2 struct { 51 Baz string 52 Qux string 53 } 54 55 func (p Param2) Double() string { 56 var runes []rune 57 for _, bRune := range p.Baz { 58 for _, qRune := range p.Qux { 59 runes = append(runes, bRune) 60 runes = append(runes, qRune) 61 } 62 } 63 return string(runes) 64 } 65 66 func printNowWithIdParam1(workId string) gokugen.WorkFnWParam { 67 return func(taskCtx context.Context, scheduled time.Time, param any) (any, error) { 68 printer(workId, taskCtx, scheduled, param.(Param1).Mix()) 69 return nil, nil 70 } 71 } 72 73 func printNowWithIdParam2(workId string) gokugen.WorkFnWParam { 74 return func(taskCtx context.Context, scheduled time.Time, param any) (any, error) { 75 printer(workId, taskCtx, scheduled, param.(Param2).Double()) 76 return nil, nil 77 } 78 } 79 80 func printer(workId string, taskCtx context.Context, scheduled time.Time, param string) { 81 now := time.Now() 82 var isCtxCancelled bool 83 select { 84 case <-taskCtx.Done(): 85 isCtxCancelled = true 86 default: 87 } 88 89 fmt.Printf( 90 "workId: %s, scheduled: %s, diff to now: %s, isCtxCancelled: %t, param: %s\n", 91 workId, 92 scheduled.Format(time.RFC3339Nano), 93 now.Sub(scheduled).String(), 94 isCtxCancelled, 95 param, 96 ) 97 } 98 99 func prepare(dbFilename string) ( 100 sched *gokugen.MiddlewareApplicator[*scheduler.Scheduler], 101 repo *repository.Sqlite3Repo, 102 workRegistory taskstorage.WorkRegistry, 103 taskStorage *taskstorage.SingleNodeTaskStorage, 104 err error, 105 ) { 106 repo, err = repository.NewSql3Repo(dbFilename) 107 if err != nil { 108 return 109 } 110 innerRegistry := &syncparam.Map[string, gokugen.WorkFnWParam]{} 111 innerRegistry.Store("func1", printNowWithIdParam1("func1")) 112 innerRegistry.Store("func2", printNowWithIdParam2("func2")) 113 innerRegistry.Store("func3", printNowWithIdParam2("func3")) 114 115 unmarshallerResgitry := &workregistry.AnyUnmarshaller{} 116 workregistry.AddType[Param1]("func1", unmarshallerResgitry) 117 workregistry.AddType[Param2]("func2", unmarshallerResgitry) 118 workregistry.AddType[Param2]("func3", unmarshallerResgitry) 119 120 workRegistory = workregistry.NewParamUnmarshaller(innerRegistry, unmarshallerResgitry) 121 122 sched = gokugen.NewMiddlewareApplicator(scheduler.NewScheduler(5, 0)) 123 124 taskStorage = taskstorage.NewSingleNodeTaskStorage( 125 repo, 126 func(ti taskstorage.TaskInfo) bool { return true }, 127 workRegistory, 128 nil, 129 ) 130 sched.Use(taskStorage.Middleware(true)...) 131 132 return 133 } 134 135 func _main() (err error) { 136 p, err := os.MkdirTemp("", "sqlite3-tmp-*") 137 if err != nil { 138 return 139 } 140 dbFilename := filepath.Join(p, "db") 141 142 sched, repo, _, _, err := prepare(dbFilename) 143 if err != nil { 144 return err 145 } 146 147 now := time.Now() 148 149 sched.Schedule( 150 gokugen.BuildContext( 151 now, 152 nil, 153 nil, 154 gokugen.WithWorkId("func1"), 155 gokugen.WithParam(Param1{Foo: "param", Bar: "qqq"}), 156 ), 157 ) 158 sched.Schedule( 159 gokugen.BuildContext( 160 now.Add(1*time.Second), 161 nil, 162 nil, 163 gokugen.WithWorkId("func2"), 164 gokugen.WithParam(Param2{Baz: "baaz", Qux: "param"}), 165 ), 166 ) 167 sched.Schedule( 168 gokugen.BuildContext( 169 now.Add(3*time.Second), 170 nil, 171 nil, 172 gokugen.WithWorkId("func3"), 173 gokugen.WithParam(Param2{Baz: "quuux", Qux: "coorrge"}), 174 ), 175 ) 176 177 ctx, cancel := context.WithDeadline(context.Background(), now.Add(2*time.Second)) 178 sched.Scheduler().Start(ctx) 179 cancel() 180 sched.Scheduler().End() 181 182 fmt.Println("after 1st teardown: tasks in repository") 183 taskInfos, err := repo.GetAll() 184 if err != nil { 185 return 186 } 187 for _, v := range taskInfos { 188 printJsonIndent(v) 189 } 190 191 sched, _, _, taskStorage, err := prepare(dbFilename) 192 if err != nil { 193 return 194 } 195 196 rescheduled, schedulingErr, err := taskStorage.Sync(sched.Schedule) 197 if err != nil { 198 return 199 } 200 fmt.Println("restoed from persistent data storage:") 201 printJsonIndent(rescheduled) 202 printJsonIndent(schedulingErr) 203 for k, v := range rescheduled { 204 fmt.Println(k, v.GetScheduledTime()) 205 } 206 207 ctx, cancel = context.WithDeadline(context.Background(), now.Add(5*time.Second)) 208 sched.Scheduler().Start(ctx) 209 cancel() 210 sched.Scheduler().End() 211 212 fmt.Println("after 2nd teardown: tasks in repository") 213 taskInfos, err = repo.GetAll() 214 if err != nil { 215 return 216 } 217 for _, v := range taskInfos { 218 printJsonIndent(v) 219 } 220 221 return 222 }