@@ -3,6 +3,7 @@ package workerpool
33import (
44 "fmt"
55 "reflect"
6+ "sync"
67)
78
89// Pool implements worker pool
@@ -11,52 +12,90 @@ type Pool interface {
1112 // will block if channel is full, you might want to wrap it with goroutine to avoid it
1213 // will panic if called after Stop()
1314 Delegate (args ... interface {})
14- // Start given number of workers that will take jobs from a queue
15- Start (maxWorkers int , fn interface {}) error
15+
16+ // AddWorker adds worker to the pool
17+ AddWorker (fn interface {}) error
18+ // RemoveWorker removes worker from the pool
19+ RemoveWorker (fn interface {}) error
20+
21+ // WorkersNum returns number of workers in the pool
22+ WorkersNum () int
1623 // Stop all workers
1724 Stop ()
1825}
1926
2027type pool struct {
2128 queue chan []reflect.Value
2229 isQueueClosed bool
30+ workers []reflect.Value
31+ mtx sync.RWMutex
2332}
2433
2534func (p * pool ) Delegate (args ... interface {}) {
2635 p .queue <- buildQueueValue (args )
2736}
2837
29- func (p * pool ) Start ( maxWorkers int , fn interface {}) error {
30- if maxWorkers < 1 {
31- return fmt . Errorf ( "Invalid number of workers: %d" , maxWorkers )
38+ func (p * pool ) AddWorker ( fn interface {}) error {
39+ if err := isValidHandler ( fn ); err != nil {
40+ return err
3241 }
3342
34- if reflect . TypeOf ( fn ). Kind () != reflect . Func {
35- return fmt .Errorf ("%s is not a reflect.Func" , reflect . TypeOf ( fn ) )
43+ if p . isQueueClosed {
44+ return fmt .Errorf ("can not add new worker to already stopped pool" )
3645 }
3746
38- if p .isQueueClosed {
39- return fmt .Errorf ("Can not start already stopped worker" )
47+ worker := reflect .ValueOf (fn )
48+
49+ go func () {
50+ for args := range p .queue {
51+ worker .Call (args )
52+ }
53+ }()
54+
55+ p .mtx .Lock ()
56+ defer p .mtx .Unlock ()
57+
58+ p .workers = append (p .workers , worker )
59+
60+ return nil
61+ }
62+
63+ func (p * pool ) RemoveWorker (fn interface {}) error {
64+ if err := isValidHandler (fn ); err != nil {
65+ return err
4066 }
4167
42- task := reflect .ValueOf (fn )
68+ rv := reflect .ValueOf (fn )
69+
70+ p .mtx .Lock ()
71+ defer p .mtx .Unlock ()
4372
44- for i := 1 ; i <= maxWorkers ; i ++ {
45- go func () {
46- for args := range p .queue {
47- task .Call (args )
48- }
49- }()
73+ for i , worker := range p .workers {
74+ if worker == rv {
75+ p .workers = append (p .workers [:i ], p .workers [i + 1 :]... )
76+ }
5077 }
5178
5279 return nil
5380}
5481
82+ func (p * pool ) WorkersNum () int {
83+ return len (p .workers )
84+ }
85+
5586func (p * pool ) Stop () {
5687 close (p .queue )
5788 p .isQueueClosed = true
5889}
5990
91+ func isValidHandler (fn interface {}) error {
92+ if reflect .TypeOf (fn ).Kind () != reflect .Func {
93+ return fmt .Errorf ("%s is not a reflect.Func" , reflect .TypeOf (fn ))
94+ }
95+
96+ return nil
97+ }
98+
6099func buildQueueValue (args []interface {}) []reflect.Value {
61100 reflectedArgs := make ([]reflect.Value , 0 )
62101
@@ -70,6 +109,7 @@ func buildQueueValue(args []interface{}) []reflect.Value {
70109// New creates new worker pool with a given job queue length
71110func New (queueLength int ) Pool {
72111 return & pool {
73- queue : make (chan []reflect.Value , queueLength ),
112+ queue : make (chan []reflect.Value , queueLength ),
113+ workers : make ([]reflect.Value , 0 ),
74114 }
75115}
0 commit comments