New chain processor
This commit is contained in:
parent
30c8711798
commit
500669b2ab
|
@ -1,5 +1,10 @@
|
||||||
package core
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
Chain struct {
|
Chain struct {
|
||||||
Flow Flow
|
Flow Flow
|
||||||
|
@ -11,8 +16,21 @@ type (
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
LF = byte(10)
|
||||||
|
)
|
||||||
|
|
||||||
func (c *Chain) Call(data []byte) (resp []byte, err error) {
|
func (c *Chain) Call(data []byte) (resp []byte, err error) {
|
||||||
return data, nil
|
switch c.Flow {
|
||||||
|
case SequentialFlow:
|
||||||
|
return c.processSequentially(data)
|
||||||
|
case ParallelFlow:
|
||||||
|
return c.processInParallel(data)
|
||||||
|
case DelayedFlow:
|
||||||
|
return c.processDelayed(data)
|
||||||
|
default:
|
||||||
|
panic("Unreachable")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Chain) Units() []string {
|
func (c *Chain) Units() []string {
|
||||||
|
@ -32,3 +50,52 @@ func (c *Chain) Units() []string {
|
||||||
|
|
||||||
return uniq
|
return uniq
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Chain) processSequentially(data []byte) (resp []byte, err error) {
|
||||||
|
for _, caller := range c.Links {
|
||||||
|
if resp, err = caller.Call(data); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Chain) processInParallel(data []byte) (resp []byte, err error) {
|
||||||
|
var (
|
||||||
|
inbox = make(chan []byte) // This channel must be unbuffered
|
||||||
|
buf bytes.Buffer
|
||||||
|
wg sync.WaitGroup
|
||||||
|
)
|
||||||
|
|
||||||
|
for _, caller := range c.Links {
|
||||||
|
wg.Add(1)
|
||||||
|
go func() {
|
||||||
|
if res, err := caller.Call(data); err == nil {
|
||||||
|
inbox <- res
|
||||||
|
}
|
||||||
|
wg.Done()
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
go func() {
|
||||||
|
wg.Wait()
|
||||||
|
close(inbox)
|
||||||
|
}()
|
||||||
|
|
||||||
|
for {
|
||||||
|
if res, ok := <-inbox; ok {
|
||||||
|
buf.Write(res)
|
||||||
|
buf.WriteByte(LF) // Add linebreak
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf.Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Chain) processDelayed(data []byte) (resp []byte, err error) {
|
||||||
|
for _, caller := range c.Links {
|
||||||
|
go caller.Call(data)
|
||||||
|
}
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
|
@ -1,142 +0,0 @@
|
||||||
package core
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"io/ioutil"
|
|
||||||
"reflect"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"code.google.com/p/go.net/context"
|
|
||||||
)
|
|
||||||
|
|
||||||
func NewChain(name string) (chain interface{}, ok bool) {
|
|
||||||
chains := readChains()
|
|
||||||
chain, ok = chains[name]
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func ProcessChain(ctx context.Context, chain interface{}) context.Context {
|
|
||||||
ctx = processSequentialChain(ctx, []interface{}{chain})
|
|
||||||
|
|
||||||
return ctx
|
|
||||||
}
|
|
||||||
|
|
||||||
func processSequentialChain(ctx context.Context, chain []interface{}) context.Context {
|
|
||||||
for _, link := range chain {
|
|
||||||
val := reflect.ValueOf(link)
|
|
||||||
|
|
||||||
switch val.Kind() {
|
|
||||||
case reflect.Map:
|
|
||||||
lmap := link.(map[string]interface{})
|
|
||||||
if subchain, ok := lmap["s"]; ok {
|
|
||||||
ctx = processSequentialChain(ctx, subchain.([]interface{}))
|
|
||||||
} else if subchain, ok := lmap["p"]; ok {
|
|
||||||
ctx = processParallelChain(ctx, subchain.([]interface{}))
|
|
||||||
} else if subchain, ok := lmap["d"]; ok {
|
|
||||||
go processSequentialChain(ctx, subchain.([]interface{}))
|
|
||||||
}
|
|
||||||
case reflect.String:
|
|
||||||
unitName := val.String()
|
|
||||||
unit, ok := Units[unitName]
|
|
||||||
if !ok {
|
|
||||||
panic("Unknown unit: " + unitName)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Execution of a unit
|
|
||||||
ctx = unit(ctx)
|
|
||||||
default:
|
|
||||||
panic("Unexpected chain element: " + val.Kind().String())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ctx
|
|
||||||
}
|
|
||||||
|
|
||||||
func processParallelChain(ctx context.Context, chain []interface{}) context.Context {
|
|
||||||
var (
|
|
||||||
wg sync.WaitGroup
|
|
||||||
contexts = make(chan context.Context, len(chain))
|
|
||||||
finished = make(chan struct{})
|
|
||||||
)
|
|
||||||
|
|
||||||
for _, link := range chain {
|
|
||||||
val := reflect.ValueOf(link)
|
|
||||||
|
|
||||||
switch val.Kind() {
|
|
||||||
case reflect.Map:
|
|
||||||
lmap := link.(map[string]interface{})
|
|
||||||
if subchain, ok := lmap["s"]; ok {
|
|
||||||
wg.Add(1)
|
|
||||||
go func(ctx context.Context) {
|
|
||||||
contexts <- processSequentialChain(ctx, subchain.([]interface{}))
|
|
||||||
wg.Done()
|
|
||||||
}(ctx)
|
|
||||||
} else if subchain, ok := lmap["p"]; ok {
|
|
||||||
wg.Add(1)
|
|
||||||
go func(ctx context.Context) {
|
|
||||||
contexts <- processParallelChain(ctx, subchain.([]interface{}))
|
|
||||||
wg.Done()
|
|
||||||
}(ctx)
|
|
||||||
} else if subchain, ok := lmap["d"]; ok {
|
|
||||||
go processSequentialChain(ctx, subchain.([]interface{}))
|
|
||||||
}
|
|
||||||
case reflect.String:
|
|
||||||
unitName := val.String()
|
|
||||||
unit, ok := Units[unitName]
|
|
||||||
if !ok {
|
|
||||||
panic("Unknown unit: " + unitName)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Execution of a unit
|
|
||||||
wg.Add(1)
|
|
||||||
go func(ctx context.Context) {
|
|
||||||
contexts <- unit(ctx)
|
|
||||||
wg.Done()
|
|
||||||
}(ctx)
|
|
||||||
default:
|
|
||||||
panic("Unexpected chain element: " + val.Kind().String())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
wg.Wait()
|
|
||||||
finished <- struct{}{}
|
|
||||||
}()
|
|
||||||
|
|
||||||
ctx = context.WithValue(ctx, "parallel_contexts", contexts)
|
|
||||||
ctx = context.WithValue(ctx, "parallel_finished", finished)
|
|
||||||
|
|
||||||
return ctx
|
|
||||||
}
|
|
||||||
|
|
||||||
func readChains() map[string]interface{} {
|
|
||||||
b, err := ioutil.ReadFile("config/chains.json")
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var chains map[string]interface{}
|
|
||||||
if err := json.Unmarshal(b, &chains); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return chains
|
|
||||||
}
|
|
||||||
|
|
||||||
func SyncronizeParallelChain(ctx context.Context, fn func(context.Context)) {
|
|
||||||
var (
|
|
||||||
pcontexts = ctx.Value("parallel_contexts").(chan context.Context)
|
|
||||||
pfinished = ctx.Value("parallel_finished").(chan struct{})
|
|
||||||
working = true
|
|
||||||
)
|
|
||||||
|
|
||||||
for len(pcontexts) > 0 || working {
|
|
||||||
select {
|
|
||||||
case pctx := <-pcontexts:
|
|
||||||
fn(pctx)
|
|
||||||
case <-pfinished:
|
|
||||||
working = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -21,7 +21,8 @@ func (s *Supervisor) StartAll() {
|
||||||
|
|
||||||
func (s *Supervisor) Start(unit string) {
|
func (s *Supervisor) Start(unit string) {
|
||||||
fmt.Println("Starting unit: " + unit)
|
fmt.Println("Starting unit: " + unit)
|
||||||
cmd := exec.Command(Conf().Python.BinPath, Conf().Python.WrapperPath, unit)
|
conf := Conf().Python
|
||||||
|
cmd := exec.Command(conf.BinPath, conf.WrapperPath, unit)
|
||||||
cmd.Stdout = os.Stdout // Sorry
|
cmd.Stdout = os.Stdout // Sorry
|
||||||
if err := cmd.Start(); err != nil {
|
if err := cmd.Start(); err != nil {
|
||||||
fmt.Println("Failed to start unit: ", unit)
|
fmt.Println("Failed to start unit: ", unit)
|
||||||
|
|
Loading…
Reference in New Issue