Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
tree: aa529b813f
Fetching contributors…

Cannot retrieve contributors at this time

file 136 lines (109 sloc) 2.665 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
package main

import (
"github.com/bketelsen/skynet"
"github.com/kballard/go-shellquote"
"go/build"
"os"
"os/exec"
"path"
"path/filepath"
"sync"
"time"
)

const RerunWait = time.Second * 5

type SubService struct {
// ServicePath is the gopath repr of the service binary
ServicePath string
// Args is the unprocessed command line arguments tacked on
// after the binary name.
Args string
// argv is Args after it is properly split up
argv []string

running bool
binPath string

rerunChan chan bool

startMutex sync.Mutex
}

func NewSubService(log skynet.Logger, servicePath, args, uuid string) (ss *SubService, err error) {
ss = &SubService{
ServicePath: servicePath,
Args: args,
// TODO: proper argument splitting
}
ss.argv, err = shellquote.Split(args)
if err != nil {
return
}

ss.argv = append([]string{"-uuid", uuid}, ss.argv...)

//verify that it exists on the local system

pkg, err := build.Import(ss.ServicePath, "", 0)
if err != nil {
return
}

if pkg.Name != "main" {
return
}

_, binName := path.Split(ss.ServicePath)
binPath := filepath.Join(pkg.BinDir, binName)
ss.binPath = binPath

return
}

func (ss *SubService) Register() {
// TODO: connect to admin port or remove this method
}

func (ss *SubService) Deregister() {
// TODO: connect to admin port or remove this method
}

func (ss *SubService) Stop() {
ss.startMutex.Lock()
defer ss.startMutex.Unlock()

if !ss.running {
return
}

ss.Deregister()
// halt the rerunner so we can kill the processes without it relaunching
ss.rerunChan <- false
}

func (ss *SubService) Start() {
ss.startMutex.Lock()
defer ss.startMutex.Unlock()

if ss.running {
return
}
ss.rerunChan = make(chan bool)

go ss.rerunner(ss.rerunChan)
// send a signal to launch the service
ss.rerunChan <- true
}

func (ss *SubService) Restart() {
ss.Stop()
ss.Start()
}

func (ss *SubService) rerunner(rerunChan chan bool) {
var proc *os.Process
for rerun := range rerunChan {
if !rerun {
break
}

cmd := exec.Command(ss.binPath, ss.argv...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr

startupTimer := time.NewTimer(RerunWait)

cmd.Start()
proc = cmd.Process

// In another goroutine, wait for the process to complete and send a relaunch signal.
// If this signal is sent after the stop signal, it is ignored.
go func(proc *os.Process) {
proc.Wait()
select {
case <-startupTimer.C:
// we let it run long enough that it might not be a recurring error, try again
rerunChan <- true
default:
// error happened too quickly - must be startup issue
startupTimer.Stop()
}
}(proc)
}
proc.Kill()
}
Something went wrong with that request. Please try again.