go-hep.org/x/hep@v0.38.1/fwk/worker.go (about)

     1  // Copyright ©2017 The go-hep Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package fwk
     6  
     7  import (
     8  	"context"
     9  	"fmt"
    10  )
    11  
    12  type workercontrol struct {
    13  	evts   chan ctxType
    14  	done   chan struct{}
    15  	errc   chan error
    16  	runctx context.Context
    17  }
    18  
    19  type worker struct {
    20  	slot int
    21  	keys []string
    22  	//store datastore
    23  	ctxs []ctxType
    24  	msg  msgstream
    25  
    26  	evts   <-chan ctxType
    27  	done   chan<- struct{}
    28  	errc   chan<- error
    29  	runctx context.Context
    30  }
    31  
    32  func newWorker(i int, app *appmgr, ctrl *workercontrol) *worker {
    33  	wrk := &worker{
    34  		slot:   i,
    35  		keys:   app.dflow.keys(),
    36  		ctxs:   make([]ctxType, len(app.tsks)),
    37  		msg:    newMsgStream(fmt.Sprintf("%s-worker-%03d", app.name, i), app.msg.lvl, nil),
    38  		evts:   ctrl.evts,
    39  		done:   ctrl.done,
    40  		errc:   ctrl.errc,
    41  		runctx: ctrl.runctx,
    42  	}
    43  	for j, tsk := range app.tsks {
    44  		wrk.ctxs[j] = ctxType{
    45  			id:   -1,
    46  			slot: i,
    47  			msg:  newMsgStream(tsk.Name(), app.msg.lvl, nil),
    48  			mgr:  nil, // nobody's supposed to access mgr's state during event-loop
    49  		}
    50  	}
    51  
    52  	go wrk.run(app.tsks)
    53  
    54  	return wrk
    55  }
    56  
    57  func (wrk *worker) run(tsks []Task) {
    58  	defer func() {
    59  		wrk.done <- struct{}{}
    60  	}()
    61  
    62  	for {
    63  		select {
    64  		case ievt, ok := <-wrk.evts:
    65  			if !ok {
    66  				return
    67  			}
    68  			wrk.runTask(wrk.runctx, ievt, tsks)
    69  
    70  		case <-wrk.runctx.Done():
    71  			//wrk.store.close()
    72  			return
    73  		}
    74  	}
    75  }
    76  
    77  func (wrk *worker) runTask(ctx context.Context, ievt ctxType, tsks []Task) {
    78  	wrk.msg.Debugf(">>> running evt=%d...\n", ievt.ID())
    79  
    80  	evtstore := ievt.store.(*datastore)
    81  	evtctx, evtCancel := context.WithCancel(wrk.runctx)
    82  	defer evtCancel()
    83  
    84  	evt := taskrunner{
    85  		ievt:   ievt.ID(),
    86  		errc:   make(chan error, len(tsks)),
    87  		evtctx: evtctx,
    88  	}
    89  	for i, tsk := range tsks {
    90  		ctx := wrk.ctxs[i]
    91  		ctx.store = evtstore
    92  		ctx.ctx = evtctx
    93  		go evt.run(i, ctx, tsk)
    94  	}
    95  	ndone := 0
    96  errloop:
    97  	for {
    98  		select {
    99  		case err, ok := <-evt.errc:
   100  			if !ok {
   101  				return
   102  			}
   103  			ndone++
   104  			if err != nil {
   105  				evtstore.close()
   106  				wrk.msg.flush()
   107  
   108  				wrk.errc <- err
   109  				return
   110  			}
   111  			if ndone == len(tsks) {
   112  				break errloop
   113  			}
   114  		case <-evtctx.Done():
   115  			evtstore.close()
   116  			wrk.msg.flush()
   117  			return
   118  		}
   119  	}
   120  	err := evtstore.reset(wrk.keys)
   121  	evtstore.close()
   122  	wrk.msg.flush()
   123  
   124  	if err != nil {
   125  		wrk.errc <- err
   126  		return
   127  	}
   128  }
   129  
   130  type taskrunner struct {
   131  	errc   chan error
   132  	evtctx context.Context
   133  
   134  	ievt int64
   135  }
   136  
   137  func (run taskrunner) run(i int, ctx ctxType, tsk Task) {
   138  	ctx.id = run.ievt
   139  	select {
   140  	case run.errc <- tsk.Process(ctx):
   141  		// FIXME(sbinet) dont be so eager to flush...
   142  		ctx.msg.flush()
   143  	case <-run.evtctx.Done():
   144  		ctx.msg.flush()
   145  	}
   146  }