ctxroutines

package module
v0.0.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 17, 2022 License: MPL-2.0 Imports: 7 Imported by: 1

README

some helpers to write common routines

GoDoc Go Report Card

Work in progress

This library is still WORK IN PROGRESS. Codes here are used in several small projects in production for few months, should be safe I think. But it still need some refinement like writting docs, better test cases and benchmarks.

Graceful shutdown made easy

func myCrawler(ctx context.Context) (err error) {
	req, err := http.NewRequestWithContext(
		ctx, "GET", "https://google.com", nil,
	)
	if err != nil {
		// log the error and
		return err
	}

	data, err := grab(req)
	if err != nil {
		// log the error and
		return
	}

	err = saveDB(ctx, data)
	// log the error and
	return
}

func main() {
	r := Loop( // infinite loop
		RunAtLeast( // do not run crawler too fast
			10*time.Second,
			CTXRunner(myCrawler),
		))

    // cancel og signal, and log the returned error
    log.Print(CancelOnSignal(r, os.Interrupt, os.Kill))
}

Race conditions

Codes in this library are thread-safe unless specified. However, thread-safety of external function is not covered.

Considering this example:

f := Loop(FuncRunner(cancel, yourFunc))

f is thread-safe iff cancel and yourFunc are thread-safe.

License

Copyright Chung-Ping Jen ronmi.ren@gmail.com 2021-

MPL v2.0

Documentation

Overview

Package ctxroutines prevides some helpers to write common routines and handle gracefully shutdown procedure

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func CancelAll

func CancelAll(rs ...Runner) context.CancelFunc

CancelAll creates a function that calls Cancel() for every Runner of rs

func CancelOnSignal

func CancelOnSignal(r Runner, sig ...os.Signal) (err error)

CancelOnSignal runs r and calls r.Cancel when receiving first signal in sig

func IsCanceled

func IsCanceled(r Runner) bool

func Run

func Run(rs ...Runner) (err []error)

Run runs every Runner of rs in separated goroutine, blocks til done, and returns all result

Types

type ErrSignalReceived added in v0.0.3

type ErrSignalReceived struct {
	os.Signal
}

ErrSignalReceived indicates the signal that SignalRunner received

func (ErrSignalReceived) Error added in v0.0.3

func (s ErrSignalReceived) Error() string

type RecordedRunner

type RecordedRunner interface {
	Runner
	Count() uint64
}

RecordedRunner is a Runner remembers how many times has been run

func Counter

func Counter(f func(uint64) error) RecordedRunner

Counter creates RecordedRunner from function

func Recorded

func Recorded(r Runner) (ret RecordedRunner)

Recorded creates a RecordedRunner

type Runner

type Runner interface {
	Context() context.Context
	Cancel()
	// Run SHOULD always return some error after canceled
	Run() error
}

Runner defines a cancelable function

func AnyErr

func AnyErr(rs ...Runner) (ret Runner)

AnyErr creates a Runner that returns first known error.

func CTXRunner

func CTXRunner(f func(context.Context) error) Runner

CTXRunner creates a Runner from a context-controlled function

Typical usage is to wrap a cancelable function for further use (like, passing to Loop()

You have to call Cancel() to release resources.

func CTXRunnerWith

func CTXRunnerWith(ctx context.Context, f func(context.Context) error) Runner

CTXRunnerWith creates a Runner from a context-controlled function with predefined context

Typical usage is to wrap a cancelable function for further use (like, passing to Loop()

You have to call Cancel() to release resources.

func FirstErr

func FirstErr(rs ...Runner) (ret Runner)

FirstErr creates a Runner that runs every Runner of rs in order, until first error occured

func FromRunner

func FromRunner(r Runner, f func() error) Runner

FromRunner reuses context and cancel function from r, but runs different function

func FuncRunner

func FuncRunner(cancel context.CancelFunc, f func() error) Runner

FuncRunner creates a runner from function

Typical usage is like FuncRunner(someStruct.Cancel, someStruct.Run) or

srv := &http.Server{Addr: ":8080"}
r := FuncRunner(srv.Shutdown, srv.ListenAndServe)

func Loop

func Loop(r Runner) (ret Runner)

Loop creates a Runner that runs r until canceled

You have to call Cancel() to release resources.

func NewRunner

func NewRunner(ctx context.Context, cancel context.CancelFunc, f func() error) Runner

NewRunner creates a basic runner

func NoCancelRunner

func NoCancelRunner(f func() error) Runner

NoCancelRunner represents a function that cannot be canceled.

In other words, Cancel() is always ignored.

func NoLessThan

func NoLessThan(dur time.Duration, f Runner) Runner

NoLessThan is a wrapper of RatelimitRunner

func NonInterruptRunner added in v0.0.2

func NonInterruptRunner(f func() error) Runner

NonInterruptRunner creates a runner that calling Cancel() does not interrupt it

In other words, Cancel() only affects further Run(), which always returns context.Canceled.

func OnceFailedWithin

func OnceFailedWithin(dur time.Duration, f Runner) (ret Runner)

OnceFailedWithin is like OnceWithin, but only failed call counts.

func OnceSuccessWithin

func OnceSuccessWithin(dur time.Duration, f Runner) (ret Runner)

OnceSuccessWithin is like OnceWithin, but only successful call counts.

func OnceWithin

func OnceWithin(dur time.Duration, f Runner) (ret Runner)

OnceWithin ensures f is not run more than once within duration dur

Additional calls are just ignored. Say you have an empty Runner f

r := OnceWithin(time.Second, f)
r.Run() // runs f
r.Run() // skipped
time.Sleep(time.Second)
r.Run() // runs f

func RatelimitRunner

func RatelimitRunner(l *rate.Limiter, r Runner) (ret Runner)

RatelimitRunner creates a Runner that respects the rate limit.

Say you have an empty Runner r with rate limit to once per second:

go r.Run() // returns immediatly
go r.Run() // returns after a second

Once the Runner has been canceled, Run() always return context.Canceled.

RatelimitRunner() looks like RunAtLeast,

func Retry

func Retry(r Runner) (ret Runner)

Retry creates a Runner runs r until it returns nil

func RetryWithCB

func RetryWithCB(r Runner, cb func(error)) (ret Runner)

RetryWithCB creates a Runner runs r until it returns nil

It calls cb if r returns error.

You have to call Cancel() to release resources.

func RetryWithChan

func RetryWithChan(r Runner, ch chan<- error) (ret Runner)

RetryWithChan is shortcut for RetryWithCB(r, func(e error) { ch <- e })

You have to call Cancel() to release resources.

func RunAtLeast

func RunAtLeast(dur time.Duration, f Runner) (ret Runner)

RunAtLeast ensures the execution time of f is longer than dur

Say you have an empty Runner f

r := RunAtLeast(time.Second, f)
r.Run() // runs f immediately, blocks 1s

func RunAtLeastFailed

func RunAtLeastFailed(dur time.Duration, f Runner) (ret Runner)

RunAtLeastFailed is like RunAtLeast, but only failed call counts

func RunAtLeastSuccess

func RunAtLeastSuccess(dur time.Duration, f Runner) (ret Runner)

RunAtLeastSuccess is like RunAtLeast, but only successful call counts

func SignalRunner added in v0.0.3

func SignalRunner(sig ...os.Signal) Runner

SignalRunner creates a Runner that waits first signal in sig and returns it as error

func Skip added in v0.0.3

func Skip(rs ...Runner) Runner

Skip creates a Runner that runs every Runner of rs in separated goroutine, returns first result and cancels others.

func SomeErr

func SomeErr(rs ...Runner) (ret Runner)

SomeErr creates a Runner runs every Runner of rs, and returns an error if there's one

  • It checks error by the order of rs
  • Returns first non-context.Canceled error
  • Returns context.Canceled if no other errors
  • Returns nil if everything's fine

func TilErr

func TilErr(r Runner) (ret Runner)

TilErr creates a Runner runs r until it returns any error

You have to call Cancel() to release resources.

func TryAtMost

func TryAtMost(n uint64, f Runner) (ret Runner)

TryAtMost creates a Runner that runs f for at most n times before it returns nil

Say you have a f only success on third try:

r := TryAtMost(5, f)
r.Run() // run f 3 times, and returs nil

r := TryAtMost(2, f)
r.Run() // run f 2 times, and returs the error from second run

r := TryAtMost(3, f)
r.Run() // run f 3 times, and returs nil

func WithPostCancel added in v0.0.4

func WithPostCancel(r Runner, cb func()) Runner

WithPostCancel creates a Runner that calls cb after executing r.Cancel()

func WithPostRun added in v0.0.4

func WithPostRun(r Runner, cb func(error)) Runner

WithPostRun creates a Runner that calls cb after executing r.Run()

func WithPreCancel added in v0.0.4

func WithPreCancel(r Runner, cb func()) Runner

WithPreCancel creates a Runner that calls cb before executing r.Cancel()

func WithPreRun added in v0.0.4

func WithPreRun(r Runner, cb func()) Runner

WithPreRun creates a Runner that calls cb before executing r.Run()

type StatefulRunner

type StatefulRunner interface {
	Runner
	IsRunning() bool
	// Try to run the Runner if it's not running. ran will be true if it runs.
	TryRun() (err error, ran bool)
	// Lock the runner, pretending that it's running. Call release() to unlock.
	// It's safe to call release more than once.
	//
	// It will block until previous Run() has finished.
	Lock() (release func())
}

StatefulRunner represents a Runner that can inspect its running state

func NewStatefulRunner

func NewStatefulRunner(f Runner) (ret StatefulRunner)

NewStatefulRunner creates a StatefulRunner from existing Runner

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL