github.com/blend/go-sdk@v1.20220411.3/examples/cron/load_test/main.go (about) 1 /* 2 3 Copyright (c) 2022 - Present. Blend Labs, Inc. All rights reserved 4 Use of this source code is governed by a MIT license that can be found in the LICENSE file. 5 6 */ 7 8 package main 9 10 import ( 11 "context" 12 "fmt" 13 "math/rand" 14 "os" 15 "sync/atomic" 16 "time" 17 18 "github.com/blend/go-sdk/cron" 19 "github.com/blend/go-sdk/logger" 20 ) 21 22 const ( 23 // N is the number of jobs to load. 24 N = 32 25 26 // Q is the total simulation time. 27 Q = 10 * time.Second 28 29 // JobRunEvery is the job interval. 30 JobRunEvery = 5 * time.Second 31 32 // JobTimeout is the timeout for the jobs. 33 JobTimeout = 3 * time.Second 34 35 // JobShortRunTime is the short run time. 36 JobShortRunTime = 2 * time.Second 37 38 // JobLongRunTime is the long run time (will induce a timeout.) 39 JobLongRunTime = 8 * time.Second 40 ) 41 42 var startedCount int32 43 var completeCount int32 44 var expectedTimeoutCount int32 45 var timeoutCount int32 46 47 var ( 48 _ cron.Job = (*loadTestJob)(nil) 49 _ cron.ScheduleProvider = (*loadTestJob)(nil) 50 _ cron.ConfigProvider = (*loadTestJob)(nil) 51 _ cron.LifecycleProvider = (*loadTestJob)(nil) 52 ) 53 54 type loadTestJob struct { 55 id int 56 running bool 57 } 58 59 func (j *loadTestJob) Name() string { 60 return fmt.Sprintf("loadTestJob_%d", j.id) 61 } 62 63 // Config returns a job config. 64 func (j *loadTestJob) Config() cron.JobConfig { 65 return cron.JobConfig{ 66 Timeout: JobTimeout, 67 } 68 } 69 70 // Lifecycle implements cron.LifecycleProvider. 71 func (j *loadTestJob) Lifecycle() cron.JobLifecycle { 72 return cron.JobLifecycle{ 73 OnCancellation: j.OnCancellation, 74 } 75 } 76 77 func (j *loadTestJob) Execute(ctx context.Context) error { 78 atomic.AddInt32(&startedCount, 1) 79 j.running = true 80 81 var runFor time.Duration 82 var randValue = rand.Float64() 83 if randValue <= 0.5 { // 50% split between short vs. long. 84 runFor = JobShortRunTime 85 } else { 86 atomic.AddInt32(&expectedTimeoutCount, 1) 87 runFor = JobLongRunTime 88 } 89 90 runForElapsed := time.After(runFor) 91 select { 92 case <-runForElapsed: 93 j.running = false 94 atomic.AddInt32(&completeCount, 1) 95 return nil 96 case <-ctx.Done(): 97 j.running = false 98 return nil 99 } 100 } 101 102 func (j *loadTestJob) OnCancellation(_ context.Context) { 103 atomic.AddInt32(&timeoutCount, 1) 104 j.running = false 105 } 106 107 func (j *loadTestJob) Status() string { 108 if j.running { 109 return "Request in progress." 110 } 111 return "Request idle." 112 } 113 114 func (j *loadTestJob) Schedule() cron.Schedule { 115 return cron.Every(JobRunEvery) 116 } 117 118 func main() { 119 jm := cron.New( 120 cron.OptLog(logger.Prod()), 121 ) 122 defer func() { 123 jm.Stop() 124 }() 125 126 if JobLongRunTime < JobTimeout { 127 fmt.Printf("Long Run Time: %v is less than the Time Out: %v\n", JobTimeout, JobLongRunTime) 128 fmt.Printf("This will cause the Completed vs. Timed Out counts to be wrong.\n") 129 os.Exit(1) 130 } 131 132 for x := 0; x < N; x++ { 133 jm.LoadJobs(&loadTestJob{id: x}) 134 } 135 fmt.Printf("Loaded %d Job Instances.\n", N) 136 fmt.Printf("Jobs run every %v\n", JobRunEvery) 137 fmt.Printf("Jobs run for %v/%v\n", JobShortRunTime, JobLongRunTime) 138 fmt.Printf("Jobs timeout %v\n", JobTimeout) 139 fmt.Println() 140 141 if err := jm.StartAsync(); err != nil { 142 logger.FatalExit(err) 143 } 144 145 time.Sleep(Q) 146 147 if err := jm.Stop(); err != nil { 148 fmt.Fprintf(os.Stderr, "error stopping job manager: %+v\n", err) 149 os.Exit(1) 150 } 151 152 // given 30 seconds total 153 // and running every 5 seconds 154 // we expect each job to run 5 times (ish) 155 156 expectedStarted := N * ((int64(Q) / int64(JobRunEvery)) - 1) 157 expectedCompleted := expectedStarted >> 1 158 159 fmt.Printf("Expected Jobs Started: %d\n", expectedStarted) 160 fmt.Printf("Actual Jobs Started: %d\n\n", startedCount) 161 162 fmt.Printf("Expected Jobs Completed: %d\n", expectedCompleted) 163 fmt.Printf("Actual Jobs Completed: %d\n\n", completeCount) 164 165 fmt.Printf("Expected Jobs Timed Out: %d\n", expectedTimeoutCount) 166 fmt.Printf("Actual Jobs Timed Out: %d\n", timeoutCount) 167 }