supervisor

package module
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Oct 5, 2016 License: MIT Imports: 5 Imported by: 1

README

Build Status

go get [-u] cirello.io/supervisor

http://godoc.org/cirello.io/supervisor

Documentation

Overview

Package supervisor provides supervisor trees for Go applications.

This package implements supervisor trees, similar to what Erlang runtime offers. It is built on top of context package, with all of its advantages, namely the possibility trickle down context-related values and cancelation signals.

A supervisor tree can be composed either of services or other supervisors - each supervisor can have its own set of configurations. Any instance of supervisor.Service can be added to a tree.

Supervisor
     ├─▶ Supervisor (if one service dies, only one is restarted)
     │       ├─▶ Service
     │       └─▶ Service
     ├─▶ Group (if one service dies, all others are restarted too)
     │       └─▶ Service
     │           Service
     │           Service
     └─▶ Service

Example:

package main

import (
	"fmt"
	"os"
	"os/signal"
	"time"

	"cirello.io/supervisor"
	"context"
)

type Simpleservice int

func (s *Simpleservice) String() string {
	return fmt.Sprintf("simple service %d", int(*s))
}

func (s *Simpleservice) Serve(ctx context.Context) {
	for {
		select {
		case <-ctx.Done():
			return
		default:
			fmt.Println("do something...")
			time.Sleep(500 * time.Millisecond)
		}
	}
}

func main(){
	svc := Simpleservice(1)
	supervisor.Add(&svc)

	// Simply, if not special context is needed:
	// supervisor.Serve()
	// Or, using context.Context to propagate behavior:
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)
	ctx, cancel := context.WithCancel(context.Background())
	go func(){
		<-c
		fmt.Println("halting supervisor...")
		cancel()
	}()
	supervisor.ServeContext(ctx)
}

TheJerf's blog post about Suture is a very good and helpful read to understand how this package has been implemented.

This is package is inspired by github.com/thejerf/suture

http://www.jerf.org/iri/post/2930

Index

Examples

Constants

View Source
const AlwaysRestart = -1

AlwaysRestart adjusts the supervisor to never halt in face of failures.

Variables

This section is empty.

Functions

func Add

func Add(service Service)

Add inserts new service into the DefaultSupervisor. If the DefaultSupervisor is already started, it will start it automatically. If the same service is added more than once, it will reset its backoff mechanism and force a service restart.

func Cancelations

func Cancelations() map[string]context.CancelFunc

Cancelations return a list of services names of DefaultSupervisor and their cancelation calls. These calls be used to force a service restart.

func Remove

func Remove(name string)

Remove stops the service in the DefaultSupervisor tree and remove from it.

func Serve

func Serve()

Serve starts the DefaultSupervisor tree. It can be started only once at a time. If stopped (canceled), it can be restarted. In case of concurrent calls, it will hang until the current call is completed. It can run only one per package-level. If you need many, use supervisor.Supervisor/supervisor.Group instead of supervisor.Serve{,Group}. After its conclusion, its internal state is reset.

Example
package main

import (
	"context"
	"fmt"
	"sync"

	"cirello.io/supervisor"
)

type Simpleservice struct {
	id int
	sync.WaitGroup
}

func (s *Simpleservice) Serve(ctx context.Context) {
	fmt.Println(s.String())
	s.Done()
	<-ctx.Done()
}

func (s *Simpleservice) String() string {
	return fmt.Sprintf("simple service %d", s.id)
}

func main() {
	svc := &Simpleservice{id: 1}
	svc.Add(1)
	supervisor.Add(svc)

	var cancel context.CancelFunc
	ctx, cancel := context.WithCancel(context.Background())
	supervisor.SetDefaultContext(ctx)
	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		supervisor.Serve()
		wg.Done()
	}()

	svc.Wait()
	cancel()
	wg.Wait()

}
Output:

simple service 1

func ServeContext

func ServeContext(ctx context.Context)

ServeContext starts the DefaultSupervisor tree with a custom context.Context. It can be started only once at a time. If stopped (canceled), it can be restarted. In case of concurrent calls, it will hang until the current call is completed. After its conclusion, its internal state is reset.

Example
package main

import (
	"context"
	"fmt"
	"sync"

	"cirello.io/supervisor"
)

type Simpleservice struct {
	id int
	sync.WaitGroup
}

func (s *Simpleservice) Serve(ctx context.Context) {
	fmt.Println(s.String())
	s.Done()
	<-ctx.Done()
}

func (s *Simpleservice) String() string {
	return fmt.Sprintf("simple service %d", s.id)
}

func main() {
	svc := &Simpleservice{id: 1}
	svc.Add(1)
	supervisor.Add(svc)

	ctx, cancel := context.WithCancel(context.Background())
	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		supervisor.ServeContext(ctx)
		wg.Done()
	}()

	svc.Wait()
	cancel()
	wg.Wait()

}
Output:

simple service 1

func ServeGroup

func ServeGroup()

ServeGroup starts the DefaultSupervisor tree within a Group. It can be started only once at a time. If stopped (canceled), it can be restarted. In case of concurrent calls, it will hang until the current call is completed. It can run only one per package-level. If you need many, use supervisor.ServeContext/supervisor.ServeGroupContext instead of supervisor.Serve/supervisor.ServeGroup. After its conclusion, its internal state is reset.

Example
package main

import (
	"context"
	"fmt"
	"sync"

	"cirello.io/supervisor"
)

type Simpleservice struct {
	id int
	sync.WaitGroup
}

func (s *Simpleservice) Serve(ctx context.Context) {
	fmt.Println(s.String())
	s.Done()
	<-ctx.Done()
}

func (s *Simpleservice) String() string {
	return fmt.Sprintf("simple service %d", s.id)
}

func main() {
	svc1 := &Simpleservice{id: 1}
	svc1.Add(1)
	supervisor.Add(svc1)
	svc2 := &Simpleservice{id: 2}
	svc2.Add(1)
	supervisor.Add(svc2)

	ctx, cancel := context.WithCancel(context.Background())
	supervisor.SetDefaultContext(ctx)
	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		supervisor.ServeGroup()
		wg.Done()
	}()

	svc1.Wait()
	svc2.Wait()
	cancel()
	wg.Wait()

}
Output:

simple service 1
simple service 2

func ServeGroupContext

func ServeGroupContext(ctx context.Context)

ServeGroupContext starts the DefaultSupervisor tree with a custom context.Context. It can be started only once at a time. If stopped (canceled), it can be restarted. In case of concurrent calls, it will hang until the current call is completed. After its conclusion, its internal state is reset.

Example
package main

import (
	"context"
	"fmt"
	"sync"

	"cirello.io/supervisor"
)

type Simpleservice struct {
	id int
	sync.WaitGroup
}

func (s *Simpleservice) Serve(ctx context.Context) {
	fmt.Println(s.String())
	s.Done()
	<-ctx.Done()
}

func (s *Simpleservice) String() string {
	return fmt.Sprintf("simple service %d", s.id)
}

func main() {
	svc1 := &Simpleservice{id: 1}
	svc1.Add(1)
	supervisor.Add(svc1)
	svc2 := &Simpleservice{id: 2}
	svc2.Add(1)
	supervisor.Add(svc2)

	ctx, cancel := context.WithCancel(context.Background())
	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		supervisor.ServeGroupContext(ctx)
		wg.Done()
	}()

	svc1.Wait()
	svc2.Wait()
	cancel()
	wg.Wait()

}
Output:

simple service 1
simple service 2

func Services

func Services() map[string]Service

Services return a list of services of DefaultSupervisor.

func SetDefaultContext

func SetDefaultContext(ctx context.Context)

SetDefaultContext allows to change the context used for supervisor.Serve() and supervisor.ServeGroup().

Types

type Group

type Group struct {
	*Supervisor
}

Group is a superset of Supervisor datastructure responsible for offering a supervisor tree whose all services are restarted whenever one of them fail or is restarted. It assumes that all services rely on each other. It does not guarantee any start other, but it does guarantee all services will be restarted. It implements Service, therefore it can be nested if necessary either with other Group or Supervisor. When passing the Group around, remind to do it as reference (&supervisor).

Example
supervisor := supervisor.Group{
	Supervisor: &supervisor.Supervisor{},
}

svc1 := &Simpleservice{id: 1}
svc1.Add(1)
supervisor.Add(svc1)
svc2 := &Simpleservice{id: 2}
svc2.Add(1)
supervisor.Add(svc2)

ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
go supervisor.Serve(ctx)

svc1.Wait()
svc2.Wait()
cancel()
Output:

func (*Group) Serve

func (g *Group) Serve(ctx context.Context)

Serve starts the Group tree. It can be started only once at a time. If stopped (canceled), it can be restarted. In case of concurrent calls, it will hang until the current call is completed.

type Service

type Service interface {
	// Serve is called by a Supervisor to start the service. It expects the
	// service to honor the passed context and its lifetime. Observe
	// <-ctx.Done() and ctx.Err(). If the service is stopped by anything
	// but the Supervisor, it will get started again. Be careful with shared
	// state among restarts.
	Serve(ctx context.Context)
}

Service is the public interface expected by a Supervisor.

This will be internally named after the result of fmt.Stringer, if available. Otherwise it will going to use an internal representation for the service name.

type ServiceType

type ServiceType int

ServiceType defines the restart strategy for a service.

const (
	// Permanent services are always restarted
	Permanent ServiceType = iota
	// Transient services are restarted only when panic.
	Transient
	// Temporary services are never restarted.
	Temporary
)

type Supervisor

type Supervisor struct {
	// Name for this supervisor tree, used for logging.
	Name string

	// MaxRestarts is the number of maximum restarts given MaxTime. If more
	// than MaxRestarts occur in the last MaxTime, then the supervisor
	// stops all services and halts. Set this to AlwaysRestart to prevent
	// supervisor halt.
	MaxRestarts int

	// MaxTime is the time period on which the internal restart count will
	// be reset.
	MaxTime time.Duration

	// Log is a replaceable function used for overall logging.
	// Default: log.Printf.
	Log func(interface{})
	// contains filtered or unexported fields
}

Supervisor is the basic datastructure responsible for offering a supervisor tree. It implements Service, therefore it can be nested if necessary. When passing the Supervisor around, remind to do it as reference (&supervisor).

Example
var supervisor supervisor.Supervisor

svc := &Simpleservice{id: 1}
svc.Add(1)
supervisor.Add(svc)

ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
go supervisor.Serve(ctx)

svc.Wait()
cancel()
Output:

var (
	// DefaultSupervisor is the default Supervisor used in this package.
	DefaultSupervisor Supervisor
)

func (*Supervisor) Add

func (s *Supervisor) Add(service Service)

Add inserts into the Supervisor tree a new permanent service. If the Supervisor is already started, it will start it automatically. If the same service is added more than once, it will reset its backoff mechanism and force a service restart.

func (*Supervisor) AddService

func (s *Supervisor) AddService(svc Service, svctype ServiceType)

AddService inserts into the Supervisor tree a new service of ServiceType. If the Supervisor is already started, it will start it automatically. If the same service is added more than once, it will reset its backoff mechanism and force a service restart.

func (*Supervisor) Cancelations

func (s *Supervisor) Cancelations() map[string]context.CancelFunc

Cancelations return a list of services names and their cancelation calls. These calls be used to force a service restart.

func (*Supervisor) Remove

func (s *Supervisor) Remove(name string)

Remove stops the service in the Supervisor tree and remove from it.

func (*Supervisor) Serve

func (s *Supervisor) Serve(ctx context.Context)

Serve starts the Supervisor tree. It can be started only once at a time. If stopped (canceled), it can be restarted. In case of concurrent calls, it will hang until the current call is completed.

func (*Supervisor) Services

func (s *Supervisor) Services() map[string]Service

Services return a list of services

func (*Supervisor) String

func (s *Supervisor) String() string

Jump to

Keyboard shortcuts

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