add functions/vendor files

This commit is contained in:
Reed Allman
2017-06-11 02:05:36 -07:00
parent 6ee9c1fa0a
commit f2c7aa5ee6
7294 changed files with 1629834 additions and 0 deletions

1
vendor/github.com/ccirello/supervisor/.gitignore generated vendored Normal file
View File

@@ -0,0 +1 @@
supervisor.test

6
vendor/github.com/ccirello/supervisor/.travis.yml generated vendored Normal file
View File

@@ -0,0 +1,6 @@
language: go
go_import_path: cirello.io/supervisor
go:
- 1.7.5
- 1.8
- tip

19
vendor/github.com/ccirello/supervisor/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,19 @@
Copyright (c) 2016 Ulderico Cirello
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE

5
vendor/github.com/ccirello/supervisor/README.md generated vendored Normal file
View File

@@ -0,0 +1,5 @@
[![Build Status](https://travis-ci.org/ucirello/supervisor.png?branch=master)](https://travis-ci.org/ucirello/supervisor)
go get [-u] cirello.io/supervisor
http://godoc.org/cirello.io/supervisor

40
vendor/github.com/ccirello/supervisor/anon.go generated vendored Normal file
View File

@@ -0,0 +1,40 @@
package supervisor
import (
"context"
"fmt"
"sync"
)
var (
universalAnonSvcMu sync.Mutex
universalAnonSvc uint64
)
func getUniversalAnonSvc() uint64 {
universalAnonSvcMu.Lock()
universalAnonSvc++
v := universalAnonSvc
universalAnonSvcMu.Unlock()
return v
}
type anonymousService struct {
id uint64
f func(context.Context)
}
func newAnonymousService(f func(context.Context)) *anonymousService {
return &anonymousService{
id: getUniversalAnonSvc(),
f: f,
}
}
func (a anonymousService) Serve(ctx context.Context) {
a.f(ctx)
}
func (a anonymousService) String() string {
return fmt.Sprintf("anonymous service %d", a.id)
}

78
vendor/github.com/ccirello/supervisor/doc.go generated vendored Normal file
View File

@@ -0,0 +1,78 @@
/*
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
*/
package supervisor // import "cirello.io/supervisor"

69
vendor/github.com/ccirello/supervisor/group.go generated vendored Normal file
View File

@@ -0,0 +1,69 @@
package supervisor
import (
"context"
"sync"
)
// 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 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
// (&group).
type Group struct {
*Supervisor
}
// 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.
func (g *Group) Serve(ctx context.Context) {
if g.Supervisor == nil {
panic("Supervisor missing for this Group.")
}
g.Supervisor.prepare()
restartCtx, cancel := context.WithCancel(ctx)
var (
mu sync.Mutex
processingFailure bool
)
processFailure := func() {
mu.Lock()
if processingFailure {
mu.Unlock()
return
}
processingFailure = true
mu.Unlock()
if !g.shouldRestart() {
cancel()
return
}
g.mu.Lock()
g.log("halting all services after failure")
for _, c := range g.terminations {
c()
}
g.cancelations = make(map[string]context.CancelFunc)
g.mu.Unlock()
go func() {
g.log("waiting for all services termination")
g.runningServices.Wait()
g.log("waiting for all services termination - completed")
mu.Lock()
processingFailure = false
mu.Unlock()
g.log("triggering group restart")
g.added <- struct{}{}
}()
}
serve(g.Supervisor, restartCtx, processFailure)
}

101
vendor/github.com/ccirello/supervisor/helpers.go generated vendored Normal file
View File

@@ -0,0 +1,101 @@
package supervisor
import (
"context"
"fmt"
"sync"
)
func serve(s *Supervisor, ctx context.Context, processFailure processFailure) {
s.running.Lock()
defer s.running.Unlock()
startServices(s, ctx, processFailure)
var wg sync.WaitGroup
wg.Add(1)
go func() {
for {
select {
case <-s.added:
startServices(s, ctx, processFailure)
case <-ctx.Done():
wg.Done()
return
}
}
}()
<-ctx.Done()
wg.Wait()
s.runningServices.Wait()
s.mu.Lock()
s.cancelations = make(map[string]context.CancelFunc)
s.mu.Unlock()
}
func startServices(s *Supervisor, supervisorCtx context.Context, processFailure processFailure) {
s.mu.Lock()
defer s.mu.Unlock()
var wg sync.WaitGroup
for _, name := range s.svcorder {
svc := s.services[name]
if _, ok := s.cancelations[name]; ok {
continue
}
wg.Add(1)
terminateCtx, terminate := context.WithCancel(supervisorCtx)
s.cancelations[name] = terminate
s.terminations[name] = terminate
go func(name string, svc service) {
s.runningServices.Add(1)
defer s.runningServices.Done()
wg.Done()
retry := true
for retry {
retry = svc.svctype == Permanent
s.log(fmt.Sprintf("%s starting", name))
func() {
defer func() {
if r := recover(); r != nil {
s.log(fmt.Sprintf("%s panic: %v", name, r))
retry = svc.svctype == Permanent || svc.svctype == Transient
}
}()
ctx, cancel := context.WithCancel(terminateCtx)
s.mu.Lock()
s.cancelations[name] = cancel
s.mu.Unlock()
svc.svc.Serve(ctx)
}()
if retry {
processFailure()
}
select {
case <-terminateCtx.Done():
s.log(fmt.Sprintf("%s restart aborted (terminated)", name))
return
case <-supervisorCtx.Done():
s.log(fmt.Sprintf("%s restart aborted (supervisor halted)", name))
return
default:
}
switch svc.svctype {
case Temporary:
s.log(fmt.Sprintf("%s exited (temporary)", name))
return
case Transient:
s.log(fmt.Sprintf("%s exited (transient)", name))
default:
s.log(fmt.Sprintf("%s exited (permanent)", name))
}
}
}(name, svc)
}
wg.Wait()
}

108
vendor/github.com/ccirello/supervisor/stdsupervisor.go generated vendored Normal file
View File

@@ -0,0 +1,108 @@
package supervisor
import (
"context"
"sync"
)
var (
defaultSupervisor Supervisor
running sync.Mutex
defaultContext = context.Background()
)
func init() {
defaultSupervisor.Name = "default supervisor"
}
// Add inserts new service into the default supervisor. If it is already
// started, it will launch it automatically.
func Add(service Service) {
defaultSupervisor.Add(service)
}
// AddFunc inserts new anonymous service into the default supervisor. If it is
// already started, it will launch it automatically.
func AddFunc(f func(context.Context)) {
defaultSupervisor.AddFunc(f)
}
// Cancelations return a list of services names of default supervisor and their
// cancelation calls. These calls be used to force a service restart.
func Cancelations() map[string]context.CancelFunc {
return defaultSupervisor.Cancelations()
}
// Remove stops the service in the default supervisor tree and remove from it.
func Remove(name string) {
defaultSupervisor.Remove(name)
}
// Serve starts the default 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. 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.
func Serve() {
running.Lock()
defaultSupervisor.Serve(defaultContext)
defaultSupervisor.reset()
defaultContext = context.Background()
running.Unlock()
}
// ServeContext starts the default upervisor 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.
func ServeContext(ctx context.Context) {
running.Lock()
defaultSupervisor.Serve(ctx)
defaultSupervisor.reset()
running.Unlock()
}
// ServeGroup starts the default supervisor 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.
func ServeGroup() {
running.Lock()
var group Group
group.Supervisor = &defaultSupervisor
group.Serve(defaultContext)
defaultSupervisor.reset()
defaultContext = context.Background()
running.Unlock()
}
// 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.
func ServeGroupContext(ctx context.Context) {
running.Lock()
var group Group
group.Supervisor = &defaultSupervisor
group.Serve(ctx)
defaultSupervisor.reset()
running.Unlock()
}
// Services return a list of services of default supervisor.
func Services() map[string]Service {
return defaultSupervisor.Services()
}
// SetDefaultContext allows to change the context used for supervisor.Serve()
// and supervisor.ServeGroup().
func SetDefaultContext(ctx context.Context) {
running.Lock()
defaultContext = ctx
running.Unlock()
}

View File

@@ -0,0 +1,147 @@
package supervisor_test
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 ExampleAddFunc() {
var svc sync.WaitGroup
svc.Add(1)
supervisor.AddFunc(func(ctx context.Context) {
fmt.Println("anonymous service")
svc.Done()
<-ctx.Done()
})
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:
// anonymous service
}
func ExampleServeContext() {
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 ExampleServeGroupContext() {
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()
// unordered output:
// simple service 1
// simple service 2
}
func ExampleServe() {
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 ExampleServeGroup() {
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()
// unordered output:
// simple service 1
// simple service 2
}

View File

@@ -0,0 +1,109 @@
package supervisor
import (
"context"
"sync"
"testing"
)
func TestAddFunc(t *testing.T) {
t.Parallel()
universalAnonSvcMu.Lock()
oldCount := universalAnonSvc
universalAnonSvc = 0
universalAnonSvcMu.Unlock()
defer func() {
universalAnonSvcMu.Lock()
universalAnonSvc = oldCount
universalAnonSvcMu.Unlock()
}()
var (
runCount int
wg sync.WaitGroup
)
wg.Add(1)
AddFunc(func(ctx context.Context) {
runCount++
wg.Done()
<-ctx.Done()
})
ctx, cancel := context.WithCancel(context.Background())
go ServeContext(ctx)
svcs := Services()
if _, ok := svcs["anonymous service 1"]; !ok {
t.Errorf("anonymous service was not found in service list")
}
wg.Wait()
cancel()
if runCount == 0 {
t.Errorf("anonymous service should have been started")
}
}
func TestDefaultSupevisorAndGroup(t *testing.T) {
t.Parallel()
svc := &holdingservice{id: 1}
svc.Add(1)
ctx, cancel := context.WithCancel(context.Background())
SetDefaultContext(ctx)
Add(svc)
if len(defaultSupervisor.services) != 1 {
t.Errorf("%s should have been added", svc.String())
}
Remove(svc.String())
if len(defaultSupervisor.services) != 0 {
t.Errorf("%s should have been removed. services: %#v", svc.String(), defaultSupervisor.services)
}
Add(svc)
svcs := Services()
if _, ok := svcs[svc.String()]; !ok {
t.Errorf("%s should have been found", svc.String())
}
var wg sync.WaitGroup
wg.Add(1)
go func() {
Serve()
wg.Done()
}()
svc.Wait()
cs := Cancelations()
if _, ok := cs[svc.String()]; !ok {
t.Errorf("%s's cancelation should have been found. %#v", svc.String(), cs)
}
cancel()
wg.Wait()
ctx, cancel = context.WithCancel(context.Background())
SetDefaultContext(ctx)
svc.Add(1)
Add(svc)
if len(defaultSupervisor.services) != 1 {
t.Errorf("%s should have been added", svc.String())
}
wg.Add(1)
go func() {
ServeGroup()
wg.Done()
}()
svc.Wait()
cancel()
wg.Wait()
}

245
vendor/github.com/ccirello/supervisor/supervisor.go generated vendored Normal file
View File

@@ -0,0 +1,245 @@
package supervisor
import (
"context"
"fmt"
"log"
"sync"
"time"
)
type service struct {
svc Service
svctype ServiceType
}
type processFailure func()
// AlwaysRestart adjusts the supervisor to never halt in face of failures.
const AlwaysRestart = -1
// ServiceType defines the restart strategy for a service.
type ServiceType int
const (
// Permanent services are always restarted
Permanent ServiceType = iota
// Transient services are restarted only when panic.
Transient
// Temporary services are never restarted.
Temporary
)
// Service is the public interface expected by a Supervisor.
//
// This will be internally named after the result of fmt.Stringer, if available.
// Otherwise it is going to use an internal representation for the service
// name.
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)
}
// 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).
// Once the supervisor is started, its attributes are frozen.
type Supervisor struct {
// Name for this supervisor tree, used for logging.
Name string
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
maxrestarts int
// MaxTime is the time period on which the internal restart count will
// be reset.
MaxTime time.Duration
maxtime time.Duration
// Log is a replaceable function used for overall logging.
// Default: log.Printf.
Log func(interface{})
log func(interface{})
// indicates that supervisor is ready for use.
prepared sync.Once
// signals that a new service has just been added, so the started
// supervisor picks it up.
added chan struct{}
// indicates that supervisor has running services.
running sync.Mutex
runningServices sync.WaitGroup
mu sync.Mutex
svcorder []string // order in which services must be started
services map[string]service // added services
cancelations map[string]context.CancelFunc // each service cancelation
terminations map[string]context.CancelFunc // each service termination call
lastRestart time.Time
restarts int
}
func (s *Supervisor) prepare() {
s.prepared.Do(s.reset)
}
func (s *Supervisor) reset() {
s.mu.Lock()
if s.Name == "" {
s.Name = "supervisor"
}
if s.MaxRestarts == 0 {
s.MaxRestarts = 5
}
if s.MaxTime == 0 {
s.MaxTime = 15 * time.Second
}
if s.Log == nil {
s.Log = func(msg interface{}) {
log.Printf("%s: %v", s.Name, msg)
}
}
s.name = s.Name
s.maxrestarts = s.MaxRestarts
s.maxtime = s.MaxTime
s.log = s.Log
s.added = make(chan struct{})
s.cancelations = make(map[string]context.CancelFunc)
s.services = make(map[string]service)
s.terminations = make(map[string]context.CancelFunc)
s.mu.Unlock()
}
func (s *Supervisor) shouldRestart() bool {
if s.maxrestarts == AlwaysRestart {
return true
}
s.mu.Lock()
defer s.mu.Unlock()
if time.Since(s.lastRestart) > s.maxtime {
s.restarts = 0
}
s.lastRestart = time.Now()
s.restarts++
return s.restarts < s.maxrestarts
}
// Cancelations return a list of services names and their cancelation calls.
// These calls be used to force a service restart.
func (s *Supervisor) Cancelations() map[string]context.CancelFunc {
svclist := make(map[string]context.CancelFunc)
s.mu.Lock()
for k, v := range s.cancelations {
svclist[k] = v
}
s.mu.Unlock()
return svclist
}
// Add inserts into the Supervisor tree a new permanent service. If the
// Supervisor is already started, it will start it automatically.
func (s *Supervisor) Add(service Service) {
s.AddService(service, Permanent)
}
// AddFunc inserts into the Supervisor tree a new permanent anonymous service.
// If the Supervisor is already started, it will start it automatically.
func (s *Supervisor) AddFunc(f func(context.Context)) {
s.AddService(newAnonymousService(f), Permanent)
}
// 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 (s *Supervisor) AddService(svc Service, svctype ServiceType) {
s.prepare()
name := fmt.Sprintf("%s", svc)
s.mu.Lock()
s.services[name] = service{
svc: svc,
svctype: svctype,
}
s.svcorder = append(s.svcorder, name)
s.mu.Unlock()
go func() {
s.added <- struct{}{}
}()
}
// Remove stops the service in the Supervisor tree and remove from it.
func (s *Supervisor) Remove(name string) {
s.prepare()
s.mu.Lock()
defer s.mu.Unlock()
if _, ok := s.services[name]; !ok {
return
}
delete(s.services, name)
for i, n := range s.svcorder {
if name == n {
s.svcorder = append(s.svcorder[:i], s.svcorder[i+1:]...)
break
}
}
if c, ok := s.terminations[name]; ok {
delete(s.terminations, name)
c()
}
if _, ok := s.cancelations[name]; ok {
delete(s.cancelations, name)
}
}
// 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 (s *Supervisor) Serve(ctx context.Context) {
s.prepare()
restartCtx, cancel := context.WithCancel(ctx)
processFailure := func() {
restart := s.shouldRestart()
if !restart {
cancel()
}
}
serve(s, restartCtx, processFailure)
}
// Services return a list of services
func (s *Supervisor) Services() map[string]Service {
svclist := make(map[string]Service)
s.mu.Lock()
for k, v := range s.services {
svclist[k] = v.svc
}
s.mu.Unlock()
return svclist
}
func (s *Supervisor) String() string {
s.prepare()
return s.name
}

View File

@@ -0,0 +1,42 @@
package supervisor_test
import (
"context"
"time"
"cirello.io/supervisor"
)
func ExampleSupervisor() {
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()
}
func ExampleGroup() {
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()
}

1072
vendor/github.com/ccirello/supervisor/supervisor_test.go generated vendored Normal file

File diff suppressed because it is too large Load Diff