mirror of
https://github.com/crazybber/go-pattern-examples.git
synced 2024-11-21 19:36:03 +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,
|
"window.autoDetectColorScheme": false,
|
||||||
"editor.tabSize": 2,
|
"editor.tabSize": 2,
|
||||||
"editor.semanticTokenColorCustomizations":{
|
"editor.semanticTokenColorCustomizations": {
|
||||||
"enabled": true, // enable semantic highlighting for all themes
|
"enabled": true, // enable semantic highlighting for all themes
|
||||||
"rules": {
|
"rules": {
|
||||||
"typeParameter": "#352cea",
|
"typeParameter": "#352cea",
|
||||||
"type": {
|
"type": {
|
||||||
"foreground": "#00aa00"
|
"foreground": "#00aa00"
|
||||||
},
|
},
|
||||||
"parameter":"#4c70e7",
|
"parameter": "#4c70e7",
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"extensions.showRecommendationsOnlyOnDemand": true,
|
"extensions.showRecommendationsOnlyOnDemand": true,
|
||||||
"files.trimTrailingWhitespace": true,
|
"files.trimTrailingWhitespace": true,
|
||||||
@ -47,9 +47,9 @@
|
|||||||
"editor.codeActionsOnSave": {
|
"editor.codeActionsOnSave": {
|
||||||
"source.organizeImports": true
|
"source.organizeImports": true
|
||||||
},
|
},
|
||||||
"fileheader.Author":"Edward",
|
"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.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",
|
"fileheader.LastModifiedBy": "Edward",
|
||||||
"peacock.color": "#5e7959"
|
"peacock.color": "#5e7959"
|
||||||
}
|
}
|
||||||
//https://vscode.readthedocs.io/en/latest/getstarted/settings/
|
//https://vscode.readthedocs.io/en/latest/getstarted/settings/
|
||||||
|
@ -2,4 +2,6 @@
|
|||||||
|
|
||||||
do a thing ,until the deadline time point
|
do a thing ,until the deadline time point
|
||||||
|
|
||||||
|
as known as timeout pattern
|
||||||
|
|
||||||
which act like time.after(), but time.after() only do once.
|
which act like time.after(), but time.after() only do once.
|
||||||
|
@ -3,10 +3,10 @@
|
|||||||
* @Author: Edward
|
* @Author: Edward
|
||||||
* @Date: 2020-06-05 12:43:39
|
* @Date: 2020-06-05 12:43:39
|
||||||
* @Last Modified by: Edward
|
* @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
|
package deadline
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -14,38 +14,42 @@ import (
|
|||||||
"time"
|
"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")
|
var ErrTimedOut = errors.New("timed out waiting for function to finish")
|
||||||
|
|
||||||
// Deadline implements the deadline/timeout resiliency pattern.
|
// Worker implements the Deadline/timeout resiliency pattern.
|
||||||
type Deadline struct {
|
// worker do the target job
|
||||||
|
type Worker struct {
|
||||||
timeout time.Duration
|
timeout time.Duration
|
||||||
action string
|
action string
|
||||||
}
|
}
|
||||||
|
|
||||||
// New constructs a new Deadline with the given timeout.
|
// New create a new Worker with the given timeout.and tile
|
||||||
func New(timeout time.Duration, sometile string) *Deadline {
|
func New(timeout time.Duration, someActionTitle string) *Worker {
|
||||||
return &Deadline{
|
return &Worker{
|
||||||
timeout: timeout,
|
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
|
// 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)
|
// 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
|
// 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.
|
// the return value of the function is returned from Run.
|
||||||
func (d *Deadline) Run(work func(<-chan struct{}) error) error {
|
func (d *Worker) Run(work func(stopperSignal chan error) error) error {
|
||||||
result := make(chan error)
|
|
||||||
|
|
||||||
stopper := make(chan struct{})
|
result := make(chan error)
|
||||||
|
//we can stop the work in advance
|
||||||
|
stopper := make(chan error, 1)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
value := work(stopper)
|
value := work(stopper)
|
||||||
select {
|
select {
|
||||||
case result <- value:
|
case result <- value:
|
||||||
case <-stopper:
|
case stopError := <-stopper:
|
||||||
|
result <- stopError
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
@ -2,64 +2,75 @@ package deadline
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"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)
|
time.Sleep(5 * time.Millisecond)
|
||||||
return nil
|
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)
|
time.Sleep(20 * time.Millisecond)
|
||||||
return nil
|
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")
|
return errors.New("foo")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMultiDeadline(t *testing.T) {
|
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)
|
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)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := dl.Run(returnsError); err.Error() != "foo" {
|
err = dl.Run(workerTakes20ms)
|
||||||
|
|
||||||
|
if err != ErrTimedOut {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
done := make(chan struct{})
|
func TestDeadline(t *testing.T) {
|
||||||
err := dl.Run(func(stopper <-chan struct{}) error {
|
|
||||||
<-stopper
|
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)
|
close(done)
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != ErrTimedOut {
|
if err != ErrTimedOut {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
<-done
|
<-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