add synchronization to prevent race condition on worker shutdown (#89)
* add synchronization to prevent race condition on worker shutdown * fix incorrect synchronization and add race unit test * fix race while broadcasting outpack
This commit is contained in:
		
							parent
							
								
									b902646ce8
								
							
						
					
					
						commit
						81d00aa9ce
					
				| @ -111,6 +111,9 @@ func (a *agent) work() { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (a *agent) disconnect_error(err error) { | func (a *agent) disconnect_error(err error) { | ||||||
|  | 	a.Lock() | ||||||
|  | 	defer a.Unlock() | ||||||
|  | 
 | ||||||
| 	if a.conn != nil { | 	if a.conn != nil { | ||||||
| 		err = &WorkerDisconnectError{ | 		err = &WorkerDisconnectError{ | ||||||
| 			err:   err, | 			err:   err, | ||||||
|  | |||||||
| @ -4,9 +4,9 @@ package worker | |||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"fmt" | 	"fmt" | ||||||
|  | 	"strconv" | ||||||
| 	"sync" | 	"sync" | ||||||
| 	"time" | 	"time" | ||||||
| 	"strconv" |  | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| const ( | const ( | ||||||
| @ -72,7 +72,7 @@ func (worker *Worker) AddServer(net, addr string) (err error) { | |||||||
| // Broadcast an outpack to all Gearman server.
 | // Broadcast an outpack to all Gearman server.
 | ||||||
| func (worker *Worker) broadcast(outpack *outPack) { | func (worker *Worker) broadcast(outpack *outPack) { | ||||||
| 	for _, v := range worker.agents { | 	for _, v := range worker.agents { | ||||||
| 		v.write(outpack) | 		v.Write(outpack) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -186,7 +186,7 @@ func (worker *Worker) Ready() (err error) { | |||||||
| 	return | 	return | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Main loop, block here
 | // Work start main loop (blocking)
 | ||||||
| // Most of time, this should be evaluated in goroutine.
 | // Most of time, this should be evaluated in goroutine.
 | ||||||
| func (worker *Worker) Work() { | func (worker *Worker) Work() { | ||||||
| 	if !worker.ready { | 	if !worker.ready { | ||||||
| @ -197,7 +197,10 @@ func (worker *Worker) Work() { | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	worker.Lock() | ||||||
| 	worker.running = true | 	worker.running = true | ||||||
|  | 	worker.Unlock() | ||||||
|  | 
 | ||||||
| 	for _, a := range worker.agents { | 	for _, a := range worker.agents { | ||||||
| 		a.Grab() | 		a.Grab() | ||||||
| 	} | 	} | ||||||
|  | |||||||
							
								
								
									
										59
									
								
								worker/worker_racy_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								worker/worker_racy_test.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,59 @@ | |||||||
|  | package worker | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"sync" | ||||||
|  | 	"testing" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func TestWorkerRace(t *testing.T) { | ||||||
|  | 	// from example worker
 | ||||||
|  | 	// An example of worker
 | ||||||
|  | 	w := New(Unlimited) | ||||||
|  | 	defer w.Close() | ||||||
|  | 	// Add a gearman job server
 | ||||||
|  | 	if err := w.AddServer(Network, "127.0.0.1:4730"); err != nil { | ||||||
|  | 		t.Fatal(err) | ||||||
|  | 	} | ||||||
|  | 	// A function for handling jobs
 | ||||||
|  | 	foobar := func(job Job) ([]byte, error) { | ||||||
|  | 		// Do nothing here
 | ||||||
|  | 		return nil, nil | ||||||
|  | 	} | ||||||
|  | 	// Add the function to worker
 | ||||||
|  | 	if err := w.AddFunc("foobar", foobar, 0); err != nil { | ||||||
|  | 		fmt.Println(err) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	var wg sync.WaitGroup | ||||||
|  | 	// A custome handler, for handling other results, eg. ECHO, dtError.
 | ||||||
|  | 	w.JobHandler = func(job Job) error { | ||||||
|  | 		if job.Err() == nil { | ||||||
|  | 			fmt.Println(string(job.Data())) | ||||||
|  | 		} else { | ||||||
|  | 			fmt.Println(job.Err()) | ||||||
|  | 		} | ||||||
|  | 		wg.Done() | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | 	// An error handler for handling worker's internal errors.
 | ||||||
|  | 	w.ErrorHandler = func(e error) { | ||||||
|  | 		fmt.Println(e) | ||||||
|  | 		// Ignore the error or shutdown the worker
 | ||||||
|  | 	} | ||||||
|  | 	// Tell Gearman job server: I'm ready!
 | ||||||
|  | 	if err := w.Ready(); err != nil { | ||||||
|  | 		fmt.Println(err) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	// Running main loop
 | ||||||
|  | 	go w.Work() | ||||||
|  | 	wg.Add(1) | ||||||
|  | 	// calling Echo
 | ||||||
|  | 	w.Echo([]byte("Hello")) | ||||||
|  | 	// Waiting results
 | ||||||
|  | 	wg.Wait() | ||||||
|  | 
 | ||||||
|  | 	// tear down
 | ||||||
|  | 	w.Close() | ||||||
|  | } | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user