mirror of
https://github.com/crazybber/go-pattern-examples.git
synced 2024-11-21 11:36:01 +03:00
finished deadline pattern
This commit is contained in:
parent
9bb39b3fdf
commit
a4a57a5556
26
.vscode/settings.json
vendored
26
.vscode/settings.json
vendored
@ -1,15 +1,15 @@
|
||||
{
|
||||
"window.autoDetectColorScheme": false,
|
||||
"editor.tabSize": 2,
|
||||
"editor.semanticTokenColorCustomizations":{
|
||||
"enabled": true, // enable semantic highlighting for all themes
|
||||
"rules": {
|
||||
"typeParameter": "#352cea",
|
||||
"type": {
|
||||
"foreground": "#00aa00"
|
||||
},
|
||||
"parameter":"#4c70e7",
|
||||
}
|
||||
"editor.semanticTokenColorCustomizations": {
|
||||
"enabled": true, // enable semantic highlighting for all themes
|
||||
"rules": {
|
||||
"typeParameter": "#352cea",
|
||||
"type": {
|
||||
"foreground": "#00aa00"
|
||||
},
|
||||
"parameter": "#4c70e7",
|
||||
}
|
||||
},
|
||||
"extensions.showRecommendationsOnlyOnDemand": true,
|
||||
"files.trimTrailingWhitespace": true,
|
||||
@ -47,9 +47,9 @@
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.organizeImports": true
|
||||
},
|
||||
"fileheader.Author":"Edward",
|
||||
"fileheader.tpl": "/*\r\n * @Description: https://github.com/crazybber\r\n * @Author: {author}\r\n * @Date: {createTime}\r\n * @Last Modified by: {lastModifiedBy}\r\n * @Last Modified time: {updateTime}\r\n */\r\n\r\n",
|
||||
"fileheader.LastModifiedBy": "Edward",
|
||||
"peacock.color": "#5e7959"
|
||||
"fileheader.Author": "Edward",
|
||||
"fileheader.tpl": "/*\r\n * @Description: https://github.com/crazybber\r\n * @Author: {author}\r\n * @Date: {createTime}\r\n * @Last Modified by: {lastModifiedBy}\r\n * @Last Modified time: {updateTime}\r\n */\r\n\r\n",
|
||||
"fileheader.LastModifiedBy": "Edward",
|
||||
"peacock.color": "#5e7959"
|
||||
}
|
||||
//https://vscode.readthedocs.io/en/latest/getstarted/settings/
|
||||
|
@ -2,4 +2,6 @@
|
||||
|
||||
do a thing ,until the deadline time point
|
||||
|
||||
as known as timeout pattern
|
||||
|
||||
which act like time.after(), but time.after() only do once.
|
||||
|
@ -3,10 +3,10 @@
|
||||
* @Author: Edward
|
||||
* @Date: 2020-06-05 12:43:39
|
||||
* @Last Modified by: Edward
|
||||
* @Last Modified time: 2020-06-05 12:56:40
|
||||
* @Last Modified time: 2020-06-05 17:34:37
|
||||
*/
|
||||
|
||||
// Package deadline implements the deadline (also known as "timeout") resiliency pattern for Go.
|
||||
// Package deadline implements deadline (also known as "timeout") resiliency pattern for Go.
|
||||
package deadline
|
||||
|
||||
import (
|
||||
@ -14,38 +14,42 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// ErrTimedOut is the error returned from Run when the deadline expires.
|
||||
// ErrTimedOut is the error returned from Run when the Worker expires.
|
||||
var ErrTimedOut = errors.New("timed out waiting for function to finish")
|
||||
|
||||
// Deadline implements the deadline/timeout resiliency pattern.
|
||||
type Deadline struct {
|
||||
// Worker implements the Deadline/timeout resiliency pattern.
|
||||
// worker do the target job
|
||||
type Worker struct {
|
||||
timeout time.Duration
|
||||
action string
|
||||
}
|
||||
|
||||
// New constructs a new Deadline with the given timeout.
|
||||
func New(timeout time.Duration, sometile string) *Deadline {
|
||||
return &Deadline{
|
||||
// New create a new Worker with the given timeout.and tile
|
||||
func New(timeout time.Duration, someActionTitle string) *Worker {
|
||||
return &Worker{
|
||||
timeout: timeout,
|
||||
action: someActionTitle,
|
||||
}
|
||||
}
|
||||
|
||||
// Run runs the given function, passing it a stopper channel. If the deadline passes before
|
||||
// Run runs the given function, passing it a stopper channel. If the Worker passes before
|
||||
// the function finishes executing, Run returns ErrTimeOut to the caller and closes the stopper
|
||||
// channel so that the work function can attempt to exit gracefully. It does not (and cannot)
|
||||
// simply kill the running function, so if it doesn't respect the stopper channel then it may
|
||||
// keep running after the deadline passes. If the function finishes before the deadline, then
|
||||
// keep running after the Worker passes. If the function finishes before the Worker, then
|
||||
// the return value of the function is returned from Run.
|
||||
func (d *Deadline) Run(work func(<-chan struct{}) error) error {
|
||||
result := make(chan error)
|
||||
func (d *Worker) Run(work func(stopperSignal chan error) error) error {
|
||||
|
||||
stopper := make(chan struct{})
|
||||
result := make(chan error)
|
||||
//we can stop the work in advance
|
||||
stopper := make(chan error, 1)
|
||||
|
||||
go func() {
|
||||
value := work(stopper)
|
||||
select {
|
||||
case result <- value:
|
||||
case <-stopper:
|
||||
case stopError := <-stopper:
|
||||
result <- stopError
|
||||
}
|
||||
}()
|
||||
|
||||
|
@ -2,64 +2,75 @@ package deadline
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func takes5ms(stopper <-chan struct{}) error {
|
||||
func workerTakes5ms(stopper chan error) error {
|
||||
fmt.Println("i'm doing this job in 5ms")
|
||||
time.Sleep(5 * time.Millisecond)
|
||||
return nil
|
||||
}
|
||||
|
||||
func takes20ms(stopper <-chan struct{}) error {
|
||||
func workerTakes20ms(stopper chan error) error {
|
||||
fmt.Println("i'm doing this job in 20ms,so work will timeout")
|
||||
time.Sleep(20 * time.Millisecond)
|
||||
return nil
|
||||
}
|
||||
|
||||
func returnsError(stopper <-chan struct{}) error {
|
||||
func cancelWork(stopper chan error) error {
|
||||
fmt.Println("i'm doing this job")
|
||||
stopper <- errors.New("canceled job") //cancel job
|
||||
time.Sleep(5 * time.Millisecond)
|
||||
fmt.Println("job canceled")
|
||||
return nil
|
||||
}
|
||||
|
||||
func returnsError(stopper chan error) error {
|
||||
fmt.Println("i'm doing this job but error occurred")
|
||||
return errors.New("foo")
|
||||
}
|
||||
|
||||
func TestMultiDeadline(t *testing.T) {
|
||||
dl := New(10*time.Millisecond, "test multi deadline case")
|
||||
|
||||
if err := dl.Run(takes5ms); err != nil {
|
||||
dl := New(15*time.Millisecond, "test multi deadline case")
|
||||
|
||||
if err := dl.Run(workerTakes5ms); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if err := dl.Run(takes20ms); err != ErrTimedOut {
|
||||
err := dl.Run(cancelWork)
|
||||
|
||||
t.Log("cancelWork error:", err)
|
||||
|
||||
if err.Error() != "canceled job" {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if err := dl.Run(returnsError); err.Error() != "foo" {
|
||||
err = dl.Run(workerTakes20ms)
|
||||
|
||||
if err != ErrTimedOut {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
done := make(chan struct{})
|
||||
err := dl.Run(func(stopper <-chan struct{}) error {
|
||||
<-stopper
|
||||
func TestDeadline(t *testing.T) {
|
||||
|
||||
dl := New(1*time.Second, "one time deadline case worker")
|
||||
|
||||
done := make(chan error)
|
||||
|
||||
err := dl.Run(func(stopper chan error) error {
|
||||
fmt.Println("i am doing something here")
|
||||
time.Sleep(time.Second * 2)
|
||||
close(done)
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != ErrTimedOut {
|
||||
t.Error(err)
|
||||
}
|
||||
<-done
|
||||
}
|
||||
|
||||
func TestDeadline(t *testing.T) {
|
||||
dl := New(1*time.Second, "one dead line case")
|
||||
|
||||
err := dl.Run(func(stopper <-chan struct{}) error {
|
||||
time.Sleep(time.Second * 10)
|
||||
return nil
|
||||
})
|
||||
|
||||
switch err {
|
||||
case ErrTimedOut:
|
||||
t.Error("execution took too long, oops")
|
||||
default:
|
||||
// some other error
|
||||
t.Log("done")
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user