gsd

package module
v0.0.0-...-a5f3ddf Latest Latest
Warning

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

Go to latest
Published: Nov 7, 2020 License: MIT Imports: 5 Imported by: 0

README

GSD – Get Sh*t Done

PkgGoDev CI

The gsd package offers a simple, no-frills way of performing arbitrary actions executed step-by-step according to a plan. It is inspired from Packer's multistep package.

Usage

// hello.go
package main

import (
    "context"
    "fmt"

    "github.com/falzm/gsd"
)

func main() {
    plan, err := gsd.NewPlan()
    if err != nil {
        // Handle error
    }

    err = plan.
        AddStep(&gsd.GenericStep{
            PreExecFunc: func(ctx context.Context, state *gsd.State) error {
                state.Store("who", "world")
                return nil
            },
            ExecFunc: func(ctx context.Context, state *gsd.State) error {
                who := state.Get("who").(string)
                fmt.Printf("Hello, %s!\n", who)
                return nil
            },
            PostExecFunc: func(ctx context.Context, state *gsd.State) error {
                state.Store("who", "universe")
                return nil
            },
        }).
        AddStep(&gsd.GenericStep{
            ExecFunc: func(ctx context.Context, state *gsd.State) error {
                who := state.Get("who").(string)
                fmt.Printf("Hello, %s!\n", who)
                return nil
            },
            CleanupFunc: func(ctx context.Context, state *gsd.State) {
                state.Delete("who")
                if _, ok := state.Load("who"); !ok {
                        fmt.Println("Goodbye, everybody!")
                }
            },
        }).
        Execute(context.Background())
        if err != nil {
                // Handle error
        }
}
$ go run hello.go
Hello, world!
Hello, universe!
Goodbye, everybody!

In addition of the GenericStep structure, the Step interface allows you to implement steps on your own structures:

// custom.go
package main

import (
	"context"
	"fmt"
	"os"

	"github.com/falzm/gsd"
)

type hello struct {
	who string
}

func (h *hello) say() {
	fmt.Printf("Hello, %s!\n", h.who)
}

func (h *hello) PreExec(_ context.Context, _ *gsd.State) error {
    h.who = os.Getenv("USER")
	return nil
}

func (h *hello) Exec(_ context.Context, _ *gsd.State) error {
	h.say()
	return nil
}

func (h *hello) PostExec(_ context.Context, _ *gsd.State) error {
	return nil
}

func (h *hello) Cleanup(_ context.Context, _ *gsd.State) {}

func (h *hello) Retries() int {
	return 0
}

func main() {
	plan, err := gsd.NewPlan()
	if err != nil {
		// Handle error
	}

	err = plan.
		AddStep(new(hello)).
		Execute(context.Background())
	if err != nil {
		// Handle error
	}
}
$ go run custom.go
Hello, marc!

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ErrCancelled = errors.New("plan execution cancelled")

ErrCancelled represents an error reported if a plan is cancelled.

View Source
var ErrTimeout = errors.New("plan execution duration limit exceeded")

ErrTimeout represents an error reported if a plan took too long to execute.

Functions

This section is empty.

Types

type GenericStep

type GenericStep struct {
	PreExecFunc  func(context.Context, *State) error
	ExecFunc     func(context.Context, *State) error
	PostExecFunc func(context.Context, *State) error
	CleanupFunc  func(context.Context, *State)
	// contains filtered or unexported fields
}

GenericStep is a generic Step implementation allowing users to provide arbitrary pre-exec/exec/post-exec/cleanup functions to be executed during the step's evaluation.

func (*GenericStep) Cleanup

func (s *GenericStep) Cleanup(ctx context.Context, state *State)

func (*GenericStep) Exec

func (s *GenericStep) Exec(ctx context.Context, state *State) error

func (*GenericStep) PostExec

func (s *GenericStep) PostExec(ctx context.Context, state *State) error

func (*GenericStep) PreExec

func (s *GenericStep) PreExec(ctx context.Context, state *State) error

func (*GenericStep) Retries

func (s *GenericStep) Retries() int

func (*GenericStep) WithRetries

func (s *GenericStep) WithRetries(n int) Step

type Plan

type Plan struct {
	// contains filtered or unexported fields
}

Plan represents a plan instance.

func NewPlan

func NewPlan(opts ...PlanOpt) (*Plan, error)

NewPlan returns a new plan.

func (*Plan) AddPause

func (p *Plan) AddPause(d time.Duration) *Plan

AddPause injects a pause of duration d after the latest step added to the plan. Note: pauses are ignored during the cleanup phase.

func (*Plan) AddStep

func (p *Plan) AddStep(step Step) *Plan

AddStep adds a new step to the plan.

func (*Plan) Execute

func (p *Plan) Execute(ctx context.Context) error

Execute executes the plan's steps sequentially until completion, or stops and returns a non-nil error if a step failed (unless the PlanOptContinueOnError option has been specified during plan creation).

func (*Plan) State

func (p *Plan) State() *State

State returns the plan's current state shared between steps.

type PlanOpt

type PlanOpt func(*Plan) error

PlanOpt represents a Plan creation option.

func PlanOptContinueOnError

func PlanOptContinueOnError() PlanOpt

PlanOptContinueOnError instructs the plan to continue its execution when one or multiple steps execution fail, whereas by default it stops at the first error encountered.

func PlanOptLimitDuration

func PlanOptLimitDuration(d time.Duration) PlanOpt

PlanOptLimitDuration instructs the plan to time out if its execution exceeds the duration d.

type State

type State struct {
	sync.Map
}

State represents a key/value map provided to the plan's steps for sharing state between steps. It is a wrapper around a sync.Map, so it is safe to be used concurrently.

func (*State) Get

func (s *State) Get(k string) interface{}

Get returns the stored value corresponding to the key k, or the nil value if the requested key is not found in the state.

type Step

type Step interface {
	// PreExec is a hook executed before the main step function.
	PreExec(context.Context, *State) error

	// Exec is the task to perform when this step of the plan is reached,
	// unless the PreExec hook returned an error.
	Exec(context.Context, *State) error

	// PostExec is a hook executed after the main step function, unless
	// the Exec() function returned an error.
	PostExec(context.Context, *State) error

	// Cleanup is a hook executed during the cleanup phase of the plan
	// execution, which consists in running the plan backwards and execute
	// each step's Cleanup sequentially (i.e. from the last recently
	// executed step up to the first).
	// Note: a step's cleanup hook is only executed if all of its *ExecFunc
	// have been executed successfully.
	Cleanup(context.Context, *State)

	// Retries return the number of times a step execution should be retried
	// upon error. Note: all *Exec functions are retried at each
	// subsequent attempt, the implementor is responsible to track the state
	// of previous attempts internally if they don't want certain functions to
	// be retried (e.g. if the Exec function has executed successfully but the
	// PostExec hook failed, the Exec function should not be re-executed). The
	// Cleanup hook is not retried.
	Retries() int
}

Step represents the interface to implement a plan step. Note: for a step to be considered as successful, all *Exec must individually be executed successfully (i.e. returned a nil error).

Jump to

Keyboard shortcuts

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