You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Example of how to record "execution duration" + run each job with an "auto cancelling" timeout.
I understand it is not mint code, so please feel free to suggest changes, or supply your own improved version.
package main
import (
"context""fmt""time""github.com/gammazero/workerpool"
)
// JobResult holds a jobs resulttypeJobResultstruct {
// PublicDatainterface{}
// Privateerrerrorruntime time.Durationnamestring
}
// Name returns name. It is written like this so the consumer// cannot change the name outside of supplying one via the Jobfunc (jr*JobResult) Name() string {
returnjr.name
}
// Runtime returns job execution runtimefunc (jr*JobResult) Runtime() time.Duration {
returnjr.runtime
}
// Error holds job errors, if anyfunc (jr*JobResult) Error() error {
returnjr.err
}
// SetError sets an error on our resultfunc (jr*JobResult) SetError(eerror) {
jr.err=e
}
// Job holds job datatypeJobstruct {
NamestringTaskfunc() JobResult
}
funcwrapJob(timeout time.Duration, resultsChanchanJobResult, jobJob) func() {
// Create our context with timeout per jobtimeoutContext, timeoutCancel:=context.WithTimeout(context.Background(), timeout)
returnfunc() {
timerStart:=time.Now()
// Start goroutine using our context, which contains our timeout.gofunc(ctx context.Context, done context.CancelFunc, resChanchanJobResult, todoJob, startTime time.Time) {
// Get result from jobresult:=todo.Task()
// Set name & execution time after job completionresult.runtime=time.Since(startTime)
result.name=todo.Name// If the timeout has been hit then `timeoutContext.Err()`// will be != nil and we should not send it on our results chan.//// Without this check we would send this job twice due to the fact// we cannot cancel in-flight requests.//// Lets say we have a long running task, how would we cancel it// in-flight? Whether http request or simply running `time.Sleep(time.Hour*999999)`?//// Instead we just don't do anything with the return, hence this check.iftimeoutContext.Err() ==nil {
resChan<-result
}
// Forcefully cancel our context.// Cancelling forcefully is not bad, essentially it means successdone()
}(timeoutContext, timeoutCancel, resultsChan, job, timerStart)
select {
// If our timeout is hit *or* cancelled forcefully, we wind up here...case<-timeoutContext.Done():
// ...that is why we check for errorswitchtimeoutContext.Err() {
// ...specifically the timeout error.casecontext.DeadlineExceeded:
// Place a result on our results channel that contains// an error, which we can check for later.resultsChan<-JobResult{
err: context.DeadlineExceeded,
name: job.Name,
runtime: time.Since(timerStart),
}
}
}
}
}
varjobs= []Job{{
Name: "job1",
Task: func() JobResult {
// THIS JOB WILL ERROR ON PURPOSE// This will surpass our timeout and should get cancelled// ...you can do whatever you want in these jobstime.Sleep(time.Second*3)
// Don't have to set the name herereturnJobResult{Data: map[string]string{"Whatever": "You want"}}
}}, {
Name: "job2",
Task: func() JobResult {
// THIS JOB WILL SUCCEEDtime.Sleep(time.Millisecond*300)
resultFromCurl:="i am a result"returnJobResult{Data: resultFromCurl}
}},
}
funcmain() {
// Set timeout here (or per job)jobTimeout:=time.Duration(time.Second*1) // 1 second// Create results channel with T type where T is whatever type you needjobResultsChannel:=make(chanJobResult, len(jobs))
// Create workerpoolnumWorkers:=10pool:=workerpool.New(numWorkers)
// Submit jobs to workerpool using our wrapper funcfor_, job:=rangejobs {
pool.Submit(wrapJob(jobTimeout, jobResultsChannel, job))
}
// Wait for jobs to finish and close results channelpool.StopWait()
close(jobResultsChannel)
// Do whatever you want with resultsforjobResult:=rangejobResultsChannel {
runTime:=int(jobResult.Runtime() /time.Millisecond)
str:="[%dms] : '%s' : JobSuccess : %s\n"data:=jobResult.DataifjobResult.Error() !=nil { // You should always check for errorsstr="[%dms] : '%s' : JobError : %s\n"data=jobResult.Error()
}
fmt.Printf(str, runTime, jobResult.Name(), data)
}
}
//// Output:// [303ms] 'job2' : JobSuccess : i am a result// [1001ms] 'job1' : JobError : context deadline exceeded
The text was updated successfully, but these errors were encountered:
Putting this here for visibility...
Example of how to record "execution duration" + run each job with an "auto cancelling" timeout.
I understand it is not mint code, so please feel free to suggest changes, or supply your own improved version.
The text was updated successfully, but these errors were encountered: