From 6f130a8c0f28daa872a88ac7ee846c8c01392a1c Mon Sep 17 00:00:00 2001 From: jeffail Date: Wed, 3 Jan 2018 23:32:41 +0000 Subject: [PATCH] Large API and logic rewrite --- README.md | 240 +++++++---------------- tunny.go | 502 ++++++++++++++++++------------------------------- tunny_logo.png | Bin 38798 -> 53281 bytes tunny_test.go | 410 ++++++++++++++++++++-------------------- worker.go | 180 ++++++++++-------- 5 files changed, 554 insertions(+), 778 deletions(-) diff --git a/README.md b/README.md index 1712d8e..b30f6d5 100644 --- a/README.md +++ b/README.md @@ -1,22 +1,35 @@ ![Tunny](tunny_logo.png "Tunny") -Tunny is a Golang library for spawning and managing a goroutine pool. +[![godoc for Jeffail/tunny][1]][2] +[![goreportcard for Jeffail/tunny][3]][4] -The API is synchronous and simple to use. Jobs are allocated to a worker when one becomes available. +Tunny is a Golang library for spawning and managing a goroutine pool, allowing +you to limit work coming from any number of goroutines with a synchronous API. -https://godoc.org/github.com/Jeffail/tunny +A fixed goroutine pool is helpful when you have work coming from an arbitrary +number of asynchronous sources, but a limited capacity for parallel processing. +For example, when processing jobs from HTTP requests that are CPU heavy you can +create a pool with a size that matches your CPU count. -## How to install: +## Install -```bash -go get github.com/jeffail/tunny +``` sh +go get github.com/Jeffail/tunny ``` -## How to use: +Or, using dep: -The most obvious use for a goroutine pool would be limiting heavy jobs to the number of CPUs available. In the example below we limit the work from arbitrary numbers of HTTP request goroutines through our pool. +``` sh +dep ensure -add github.com/Jeffail/tunny +``` + +## Use -```go +For most cases your heavy work can be expressed in a simple `func()`, where you +can use `NewFunc`. Let's see how this looks using our HTTP requests to CPU count +example: + +``` go package main import ( @@ -24,22 +37,19 @@ import ( "net/http" "runtime" - "github.com/jeffail/tunny" + "github.com/Jeffail/tunny" ) func main() { numCPUs := runtime.NumCPU() - runtime.GOMAXPROCS(numCPUs+1) // numCPUs hot threads + one for async tasks. - - pool, _ := tunny.CreatePool(numCPUs, func(object interface{}) interface{} { - input, _ := object.([]byte) - // Do something that takes a lot of work - output := input + pool := tunny.NewFunc(numCPUs, func(payload interface{}) interface{} { + var result []byte - return output - }).Open() + // TODO: Something CPU heavy with payload + return result + }) defer pool.Close() http.HandleFunc("/work", func(w http.ResponseWriter, r *http.Request) { @@ -47,9 +57,11 @@ func main() { if err != nil { http.Error(w, "Internal error", http.StatusInternalServerError) } + defer r.Body.Close() - // Send work to our pool - result, _ := pool.SendWork(input) + // Funnel this work into our pool. This call is synchronous and will + // block until the job is completed. + result := pool.Process(input) w.Write(result.([]byte)) }) @@ -58,172 +70,56 @@ func main() { } ``` -Tunny supports timeouts. You can replace the `SendWork` call above to the following: - -```go - // Or, alternatively, send it with a timeout (in this case 5 seconds). - result, err := pool.SendWorkTimed(5000, input) - if err != nil { - http.Error(w, "Request timed out", http.StatusRequestTimeout) - } -``` - -## Can I send a closure instead of data? - -Yes, the arguments passed to the worker are boxed as interface{}, so this can actually be a func, you can implement this yourself, or if you're not bothered about return values you can use: - -```go -exampleChannel := make(chan int) - -pool, _ := tunny.CreatePoolGeneric(numCPUs).Open() - -err := pool.SendWork(func() { - /* Do your hard work here, usual rules of closures apply here, - * so you can return values like so: - */ - exampleChannel <- 10 -}) +Tunny also supports timeouts. You can replace the `Process` call above to the +following: -if err != nil { - // You done goofed +``` go +result, err := pool.ProcessTimed(input, time.Second*5) +if err == tunny.ErrJobTimedOut { + http.Error(w, "Request timed out", http.StatusRequestTimeout) } ``` -## How do I give my workers state? - -Tunny workers implement the `TunnyWorkers` interface, simply implement this interface to have your own objects (and state) act as your workers. +## Changing Pool Size -```go -/* -TunnyWorker - The basic interface of a tunny worker. -*/ -type TunnyWorker interface { +The size of a Tunny pool can be changed at any time with `SetSize(int)`: - // Called for each job, expects the result to be returned synchronously - TunnyJob(interface{}) interface{} - - // Called after each job, this indicates whether the worker is ready for the next job. - // The default implementation is to return true always. If false is returned then the - // method is called every five milliseconds until either true is returned or the pool - // is closed. - TunnyReady() bool -} +``` go +pool.SetSize(10) // 10 goroutines +pool.SetSize(100) // 100 goroutines ``` -Here is a short example: - -```go -type customWorker struct { - // TODO: Put some state here -} - -// Use this call to block further jobs if necessary -func (worker *customWorker) TunnyReady() bool { - return true -} - -// This is where the work actually happens -func (worker *customWorker) TunnyJob(data interface{}) interface{} { - /* TODO: Use and modify state - * there's no need for thread safety paradigms here unless the - * data is being accessed from another goroutine outside of - * the pool. - */ - if outputStr, ok := data.(string); ok { - return ("custom job done: " + outputStr) - } - return nil -} - -func TestCustomWorkers (t *testing.T) { - outChan := make(chan int, 10) +This is safe to perform from any goroutine even if others are still processing. - wg := new(sync.WaitGroup) - wg.Add(10) +## Goroutines With State - workers := make([]tunny.TunnyWorker, 4) - for i, _ := range workers { - workers[i] = &(customWorker{}) - } - - pool, _ := tunny.CreateCustomPool(workers).Open() - - defer pool.Close() +Sometimes each goroutine within a Tunny pool will require its own managed state. +In this case you should implement [`tunny.Worker`][tunny-worker], which includes +calls for terminating, interrupting (in case a job times out and is no longer +needed) and blocking the next job allocation until a condition is met. - for i := 0; i < 10; i++ { - go func() { - value, _ := pool.SendWork("hello world") - fmt.Println(value.(string)) +When creating a pool using `Worker` types you will need to provide a constructor +function for spawning your custom implementation: - wg.Done() - }() - } - - wg.Wait() -} -``` - -The TunnyReady method allows you to use your state to determine whether or not a worker should take on another job. For example, your worker could hold a counter of how many jobs it has done, and perhaps after a certain amount it should perform another act before taking on more work, it's important to use TunnyReady for these occasions since blocking the TunnyJob call will hold up the waiting client. - -It is recommended that you do not block TunnyReady() whilst you wait for some condition to change, since this can prevent the pool from closing the worker goroutines. Currently, TunnyReady is called at 5 millisecond intervals until you answer true or the pool is closed. - -## I need more control - -You crazy fool, let's take this up to the next level. You can optionally implement `TunnyExtendedWorker` for more control. - -```go -/* -TunnyExtendedWorker - An optional interface that can be implemented if the worker needs -more control over its state. -*/ -type TunnyExtendedWorker interface { - - // Called when the pool is opened, this will be called before any jobs are sent. - TunnyInitialize() - - // Called when the pool is closed, this will be called after all jobs are completed. - TunnyTerminate() -} -``` - -## Can a worker detect when a timeout occurs? - -Yes, you can also implement the `TunnyInterruptable` interface. - -```go -/* -TunnyInterruptable - An optional interface that can be implemented in order to allow the -worker to drop jobs when they are abandoned. -*/ -type TunnyInterruptable interface { - - // Called when the current job has been abandoned by the client. - TunnyInterrupt() -} +``` go +pool := tunny.New(poolSize, func() Worker { + // TODO: Any per-goroutine state allocation here. + return newCustomWorker() +}) ``` -This method will be called in the event that a timeout occurs whilst waiting for the result. `TunnyInterrupt` is called from a newly spawned goroutine, so you'll need to create your own mechanism for stopping your worker mid-way through a job. - -## Can SendWork be called asynchronously? - -There are the helper functions SendWorkAsync and SendWorkTimedAsync, that are the same as their respective sync calls with an optional second argument func(interface{}, error), this is the call made when a result is returned and can be nil if there is no need for the closure. - -However, if you find yourself in a situation where the sync return is not necessary then chances are you don't actually need Tunny at all. Golang is all about making concurrent programming simple by nature, and using Tunny for implementing simple async worker calls defeats the great work of the language spec and adds overhead that isn't necessary. - -## Behaviours and caveats: - -### - Workers request jobs on an ad-hoc basis - -When there is a backlog of jobs waiting to be serviced, and all workers are occupied, a job will not be assigned to a worker until it is already prepared for its next job. This means workers do not develop their own individual queues. Instead, the backlog is shared by the entire pool. - -This means an individual worker is able to halt, or spend exceptional lengths of time on a single request without hindering the flow of any other requests, provided there are other active workers in the pool. - -### - A job can be dropped before work is begun - -Tunny has support for specified timeouts at the work request level, if this timeout is triggered whilst waiting for a worker to become available then the request is dropped entirely and no effort is wasted on the abandoned request. +This allows Tunny to create and destroy `Worker` types cleanly when the pool +size is changed. -### - Backlogged jobs are FIFO, for now +## Ordering -When a job arrives and all workers are occupied the waiting thread will lock at a select block whilst waiting to be assigned a worker. In practice this seems to create a FIFO queue, implying that this is how the implementation of Golang has dealt with select blocks, channels and multiple reading goroutines. +Backlogged jobs are not guaranteed to be processed in order. Due to the current +implementation of channels and select blocks a stack of backlogged jobs will be +processed as a FIFO queue. However, this behaviour is not part of the spec and +should not be relied upon. -However, I haven't found a guarantee of this behaviour in the Golang documentation, so I cannot guarantee that this will always be the case. +[1]: https://godoc.org/github.com/Jeffail/tunny?status.svg +[2]: http://godoc.org/github.com/Jeffail/tunny +[3]: https://goreportcard.com/badge/github.com/Jeffail/tunny +[4]: https://goreportcard.com/report/Jeffail/tunny +[tunny-worker]: https://godoc.org/github.com/Jeffail/tunny#Worker diff --git a/tunny.go b/tunny.go index 96b1032..c83ccfa 100644 --- a/tunny.go +++ b/tunny.go @@ -1,379 +1,253 @@ -/* -Copyright (c) 2014 Ashley Jeffs - -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. -*/ - -// Package tunny implements a simple pool for maintaining independant worker goroutines. +// Copyright (c) 2014 Ashley Jeffs +// +// 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. + package tunny import ( "errors" - "expvar" - "reflect" - "strconv" "sync" - "sync/atomic" "time" ) +//------------------------------------------------------------------------------ + // Errors that are used throughout the Tunny API. var ( - ErrPoolAlreadyRunning = errors.New("the pool is already running") - ErrPoolNotRunning = errors.New("the pool is not running") - ErrJobNotFunc = errors.New("generic worker not given a func()") - ErrWorkerClosed = errors.New("worker was closed") - ErrJobTimedOut = errors.New("job request timed out") + ErrPoolNotRunning = errors.New("the pool is not running") + ErrJobNotFunc = errors.New("generic worker not given a func()") + ErrWorkerClosed = errors.New("worker was closed") + ErrJobTimedOut = errors.New("job request timed out") ) -/* -TunnyWorker - The basic interface of a tunny worker. -*/ -type TunnyWorker interface { - - // Called for each job, expects the result to be returned synchronously - TunnyJob(interface{}) interface{} +// Worker is an interface representing a Tunny working agent. It will be used to +// block a calling goroutine until ready to process a job, process that job +// synchronously, interrupt its own process call when jobs are abandoned, and +// clean up its resources when being removed from the pool. +// +// Each of these duties are implemented as a single method and can be averted +// when not needed by simply implementing an empty func. +type Worker interface { + // Process will synchronously perform a job and return the result. + Process(interface{}) interface{} - // Called after each job, this indicates whether the worker is ready for the next job. - // The default implementation is to return true always. If false is returned then the - // method is called every five milliseconds until either true is returned or the pool - // is closed. For efficiency you should have this call block until your worker is ready, - // otherwise you introduce a 5ms latency between jobs. - TunnyReady() bool -} - -/* -TunnyExtendedWorker - An optional interface that can be implemented if the worker needs -more control over its state. -*/ -type TunnyExtendedWorker interface { + // BlockUntilReady is called before each job is processed and must block the + // calling goroutine until the Worker is ready to process the next job. + BlockUntilReady() - // Called when the pool is opened, this will be called before any jobs are sent. - TunnyInitialize() + // Interrupt is called when a job is cancelled. The worker is responsible + // for unblocking the Process implementation. + Interrupt() - // Called when the pool is closed, this will be called after all jobs are completed. - TunnyTerminate() + // Terminate is called when a Worker is removed from the processing pool + // and is responsible for cleaning up any held resources. + Terminate() } -/* -TunnyInterruptable - An optional interface that can be implemented in order to allow the -worker to drop jobs when they are abandoned. -*/ -type TunnyInterruptable interface { - - // Called when the current job has been abandoned by the client. - TunnyInterrupt() -} +//------------------------------------------------------------------------------ -/* -Default and very basic implementation of a tunny worker. This worker holds a closure which -is assigned at construction, and this closure is called on each job. -*/ -type tunnyDefaultWorker struct { - job *func(interface{}) interface{} +// closureWorker is a minimal Worker implementation that simply wraps a +// func(interface{}) interface{} +type closureWorker struct { + processor func(interface{}) interface{} } -func (worker *tunnyDefaultWorker) TunnyJob(data interface{}) interface{} { - return (*worker.job)(data) +func (w *closureWorker) Process(payload interface{}) interface{} { + return w.processor(payload) } -func (worker *tunnyDefaultWorker) TunnyReady() bool { - return true -} +func (w *closureWorker) BlockUntilReady() {} +func (w *closureWorker) Interrupt() {} +func (w *closureWorker) Terminate() {} -/* -WorkPool contains the structures and methods required to communicate with your pool, it must -be opened before sending work and closed when all jobs are completed. - -You may open and close a pool as many times as you wish, calling close is a blocking call that -guarantees all goroutines are stopped. -*/ -type WorkPool struct { - workers []*workerWrapper - selects []reflect.SelectCase - statusMutex sync.RWMutex - running uint32 - pendingAsyncJobs int32 -} +//------------------------------------------------------------------------------ -func (pool *WorkPool) isRunning() bool { - return (atomic.LoadUint32(&pool.running) == 1) -} +// callbackWorker is a minimal Worker implementation that attempts to cast +// each job into func() and either calls it if successful or returns +// ErrJobNotFunc. +type callbackWorker struct{} -func (pool *WorkPool) setRunning(running bool) { - if running { - atomic.SwapUint32(&pool.running, 1) - } else { - atomic.SwapUint32(&pool.running, 0) +func (w *callbackWorker) Process(payload interface{}) interface{} { + f, ok := payload.(func()) + if !ok { + return ErrJobNotFunc } + f() + return nil } -/* -Open all channels and launch the background goroutines managed by the pool. -*/ -func (pool *WorkPool) Open() (*WorkPool, error) { - pool.statusMutex.Lock() - defer pool.statusMutex.Unlock() +func (w *callbackWorker) BlockUntilReady() {} +func (w *callbackWorker) Interrupt() {} +func (w *callbackWorker) Terminate() {} + +//------------------------------------------------------------------------------ - if !pool.isRunning() { +// Pool is a struct that manages a collection of workers, each with their own +// goroutine. The Pool can initialize, expand, compress and close the workers, +// as well as processing jobs with the workers synchronously. +type Pool struct { + ctor func() Worker + workers []*workerWrapper + reqChan chan workRequest - pool.selects = make([]reflect.SelectCase, len(pool.workers)) + workerMut sync.Mutex +} - for i, workerWrapper := range pool.workers { - workerWrapper.Open() +// New creates a new Pool of workers that starts with n workers. You must +// provide a constructor function that creates new Worker types and when you +// change the size of the pool the constructor will be called to create each new +// Worker. +func New(n int, ctor func() Worker) *Pool { + p := &Pool{ + ctor: ctor, + reqChan: make(chan workRequest), + } + p.SetSize(n) - pool.selects[i] = reflect.SelectCase{ - Dir: reflect.SelectRecv, - Chan: reflect.ValueOf(workerWrapper.readyChan), - } - } + return p +} - pool.setRunning(true) - return pool, nil +// NewFunc creates a new Pool of workers where each worker will process using +// the provided func. +func NewFunc(n int, f func(interface{}) interface{}) *Pool { + return New(n, func() Worker { + return &closureWorker{ + processor: f, + } + }) +} - } - return nil, ErrPoolAlreadyRunning +// NewCallback creates a new Pool of workers where workers cast the job payload +// into a func() and runs it, or returns ErrNotFunc if the cast failed. +func NewCallback(n int) *Pool { + return New(n, func() Worker { + return &callbackWorker{} + }) } -/* -Close all channels and goroutines managed by the pool. -*/ -func (pool *WorkPool) Close() error { - pool.statusMutex.Lock() - defer pool.statusMutex.Unlock() +//------------------------------------------------------------------------------ - if pool.isRunning() { - for _, workerWrapper := range pool.workers { - workerWrapper.Close() - } - for _, workerWrapper := range pool.workers { - workerWrapper.Join() - } - pool.setRunning(false) - return nil +// Process will use the Pool to process a payload and synchronously return the +// result. Process can be called safely by any goroutines, but will panic if the +// Pool has been stopped. +func (p *Pool) Process(payload interface{}) interface{} { + request, open := <-p.reqChan + if !open { + panic(ErrPoolNotRunning) } - return ErrPoolNotRunning -} -/* -CreatePool - Creates a pool of workers, and takes a closure argument which is the action -to perform for each job. -*/ -func CreatePool(numWorkers int, job func(interface{}) interface{}) *WorkPool { - pool := WorkPool{running: 0} - - pool.workers = make([]*workerWrapper, numWorkers) - for i := range pool.workers { - newWorker := workerWrapper{ - worker: &(tunnyDefaultWorker{&job}), - } - pool.workers[i] = &newWorker + request.jobChan <- payload + + payload, open = <-request.retChan + if !open { + panic(ErrWorkerClosed) } - return &pool + return payload } -/* -CreatePoolGeneric - Creates a pool of generic workers. When sending work to a pool of -generic workers you send a closure (func()) which is the job to perform. -*/ -func CreatePoolGeneric(numWorkers int) *WorkPool { - - return CreatePool(numWorkers, func(jobCall interface{}) interface{} { - if method, ok := jobCall.(func()); ok { - method() - return nil - } - return ErrJobNotFunc - }) +// ProcessTimed will use the Pool to process a payload and synchronously return +// the result. If the timeout occurs before the job has finished the worker will +// be interrupted and ErrJobTimedOut will be returned. ProcessTimed can be +// called safely by any goroutines. +func (p *Pool) ProcessTimed( + payload interface{}, + timeout time.Duration, +) (interface{}, error) { + tout := time.NewTimer(timeout) -} + var request workRequest + var open bool -/* -CreateCustomPool - Creates a pool for an array of custom workers. The custom workers -must implement TunnyWorker, and may also optionally implement TunnyExtendedWorker and -TunnyInterruptable. -*/ -func CreateCustomPool(customWorkers []TunnyWorker) *WorkPool { - pool := WorkPool{running: 0} - - pool.workers = make([]*workerWrapper, len(customWorkers)) - for i := range pool.workers { - newWorker := workerWrapper{ - worker: customWorkers[i], + select { + case request, open = <-p.reqChan: + if !open { + return nil, ErrPoolNotRunning } - pool.workers[i] = &newWorker + case <-tout.C: + return nil, ErrJobTimedOut } - return &pool -} + select { + case request.jobChan <- payload: + case <-tout.C: + request.interruptFunc() + return nil, ErrJobTimedOut + } -/* -SendWorkTimed - Send a job to a worker and return the result, this is a synchronous -call with a timeout. -*/ -func (pool *WorkPool) SendWorkTimed(milliTimeout time.Duration, jobData interface{}) (interface{}, error) { - pool.statusMutex.RLock() - defer pool.statusMutex.RUnlock() - - if pool.isRunning() { - before := time.Now() - - // Create a new time out timer - timeout := time.NewTimer(milliTimeout * time.Millisecond) - defer timeout.Stop() - - // Create new selectcase[] and add time out case - selectCases := append(pool.selects[:], reflect.SelectCase{ - Dir: reflect.SelectRecv, - Chan: reflect.ValueOf(timeout.C), - }) - - // Wait for workers, or time out - if chosen, _, ok := reflect.Select(selectCases); ok { - - // Check if the selected index is a worker, otherwise we timed out - if chosen < (len(selectCases) - 1) { - pool.workers[chosen].jobChan <- jobData - - timeoutRemain := time.NewTimer((milliTimeout * time.Millisecond) - time.Since(before)) - defer timeoutRemain.Stop() - - // Wait for response, or time out - select { - case data, open := <-pool.workers[chosen].outputChan: - if !open { - return nil, ErrWorkerClosed - } - return data, nil - case <-timeoutRemain.C: - /* If we time out here we also need to ensure that the output is still - * collected and that the worker can move on. Therefore, we fork the - * waiting process into a new goroutine. - */ - go func() { - pool.workers[chosen].Interrupt() - <-pool.workers[chosen].outputChan - }() - return nil, ErrJobTimedOut - } - } else { - return nil, ErrJobTimedOut - } - } else { - // This means the chosen channel was closed + select { + case payload, open = <-request.retChan: + if !open { return nil, ErrWorkerClosed } - } else { - return nil, ErrPoolNotRunning + case <-tout.C: + request.interruptFunc() + return nil, ErrJobTimedOut } -} -/* -SendWorkTimedAsync - Send a timed job to a worker without blocking, and optionally -send the result to a receiving closure. You may set the closure to nil if no -further actions are required. -*/ -func (pool *WorkPool) SendWorkTimedAsync( - milliTimeout time.Duration, - jobData interface{}, - after func(interface{}, error), -) { - atomic.AddInt32(&pool.pendingAsyncJobs, 1) - go func() { - defer atomic.AddInt32(&pool.pendingAsyncJobs, -1) - result, err := pool.SendWorkTimed(milliTimeout, jobData) - if after != nil { - after(result, err) - } - }() + tout.Stop() + return payload, nil } -/* -SendWork - Send a job to a worker and return the result, this is a synchronous call. -*/ -func (pool *WorkPool) SendWork(jobData interface{}) (interface{}, error) { - pool.statusMutex.RLock() - defer pool.statusMutex.RUnlock() - - if pool.isRunning() { - if chosen, _, ok := reflect.Select(pool.selects); ok && chosen >= 0 { - pool.workers[chosen].jobChan <- jobData - result, open := <-pool.workers[chosen].outputChan - - if !open { - return nil, ErrWorkerClosed - } - return result, nil - } - return nil, ErrWorkerClosed +// SetSize changes the total number of workers in the Pool. This can be called +// by any goroutine at any time unless the Pool has been stopped, in which case +// a panic will occur. +func (p *Pool) SetSize(n int) { + p.workerMut.Lock() + defer p.workerMut.Unlock() + + lWorkers := len(p.workers) + if lWorkers == n { + return } - return nil, ErrPoolNotRunning -} -/* -SendWorkAsync - Send a job to a worker without blocking, and optionally send the -result to a receiving closure. You may set the closure to nil if no further actions -are required. -*/ -func (pool *WorkPool) SendWorkAsync(jobData interface{}, after func(interface{}, error)) { - atomic.AddInt32(&pool.pendingAsyncJobs, 1) - go func() { - defer atomic.AddInt32(&pool.pendingAsyncJobs, -1) - result, err := pool.SendWork(jobData) - if after != nil { - after(result, err) - } - }() -} + // Add extra workers if N > len(workers) + for i := lWorkers; i < n; i++ { + p.workers = append(p.workers, newWorkerWrapper(p.reqChan, p.ctor())) + } -/* -NumPendingAsyncJobs - Get the current count of async jobs either in flight, or waiting for a worker -*/ -func (pool *WorkPool) NumPendingAsyncJobs() int32 { - return atomic.LoadInt32(&pool.pendingAsyncJobs) -} + // Asynchronously stop all workers > N + for i := n; i < lWorkers; i++ { + p.workers[i].stop() + } + + // Synchronously wait for all workers > N to stop + for i := n; i < lWorkers; i++ { + p.workers[i].join() + } -/* -NumWorkers - Number of workers in the pool -*/ -func (pool *WorkPool) NumWorkers() int { - return len(pool.workers) + // Remove stopped workers from slice + p.workers = p.workers[:n] } -type liveVarAccessor func() string +// GetSize returns the current size of the pool. +func (p *Pool) GetSize() int { + p.workerMut.Lock() + defer p.workerMut.Unlock() -func (a liveVarAccessor) String() string { - return a() + return len(p.workers) } -/* -PublishExpvarMetrics - Publishes the NumWorkers and NumPendingAsyncJobs to expvars -*/ -func (pool *WorkPool) PublishExpvarMetrics(poolName string) { - ret := expvar.NewMap(poolName) - asyncJobsFn := func() string { - return strconv.FormatInt(int64(pool.NumPendingAsyncJobs()), 10) - } - numWorkersFn := func() string { - return strconv.FormatInt(int64(pool.NumWorkers()), 10) - } - ret.Set("pendingAsyncJobs", liveVarAccessor(asyncJobsFn)) - ret.Set("numWorkers", liveVarAccessor(numWorkersFn)) +// Close will terminate all workers and close the job channel of this Pool. +func (p *Pool) Close() { + p.SetSize(0) + close(p.reqChan) } + +//------------------------------------------------------------------------------ diff --git a/tunny_logo.png b/tunny_logo.png index 36028decfd1a4ae8c880bdc02aa76267e0e0fe8f..16b7b73b5d90b3e458929303c8b5c38f22f7d46a 100644 GIT binary patch literal 53281 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 literal 38798 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 sylJ>AT0XW8ycR|M|3v+N7qE9pBsun__h6Z false loop - atomic.SwapUint32(&wrapper.poolOpen, uint32(0)) +func (w *workerWrapper) interrupt() { + close(w.interruptChan) + w.worker.Interrupt() } -func (wrapper *workerWrapper) Join() { - // Ensure that both the ready and output channels are closed +func (w *workerWrapper) run() { + jobChan, retChan := make(chan interface{}), make(chan interface{}) + defer func() { + w.worker.Terminate() + close(retChan) + close(w.closedChan) + }() + for { - _, readyOpen := <-wrapper.readyChan - _, outputOpen := <-wrapper.outputChan - if !readyOpen && !outputOpen { - break + // NOTE: Blocking here will prevent the worker from closing down. + w.worker.BlockUntilReady() + select { + case w.reqChan <- workRequest{ + jobChan: jobChan, + retChan: retChan, + interruptFunc: w.interrupt, + }: + select { + case payload := <-jobChan: + result := w.worker.Process(payload) + select { + case retChan <- result: + case <-w.interruptChan: + w.interruptChan = make(chan struct{}) + } + case _, _ = <-w.interruptChan: + w.interruptChan = make(chan struct{}) + } + case <-w.closeChan: + return } } +} - if extWorker, ok := wrapper.worker.(TunnyExtendedWorker); ok { - extWorker.TunnyTerminate() - } +//------------------------------------------------------------------------------ + +func (w *workerWrapper) stop() { + close(w.closeChan) } -func (wrapper *workerWrapper) Interrupt() { - if extWorker, ok := wrapper.worker.(TunnyInterruptable); ok { - extWorker.TunnyInterrupt() - } +func (w *workerWrapper) join() { + <-w.closedChan } + +//------------------------------------------------------------------------------