From 6460f712850d2af1e97d429fc42dd96531b15fc1 Mon Sep 17 00:00:00 2001 From: Anatolii B Date: Tue, 7 May 2019 12:53:00 -0700 Subject: [PATCH] Mitigate race condition (#11) * Mitigate work complete race condition * Rearrange race mitigation to have no penalty for regular outcomes If the job response arrives not too early after submission we wont have any delay penalty * Use const for work handle delay --- client/client.go | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/client/client.go b/client/client.go index b94a21c..c985849 100644 --- a/client/client.go +++ b/client/client.go @@ -24,6 +24,10 @@ var ( NullBytes = []byte{Null} ) +const ( + WORK_HANDLE_DELAY_MS = 5 // milliseconds delay for re-try processing of work completion requests if handler hasn't been yet stored in hash map. +) + type connection struct { // This simple wrapper struct is just a convenient way to deal with the // fact that accessing the underlying pointer for an interface value type @@ -426,14 +430,21 @@ func (client *Client) process(resp *Response) { case rt.PT_WorkData, rt.PT_WorkWarning, rt.PT_WorkStatus: // These alternate conditions should not happen so long as // everyone is following the specification. - if handler, ok := client.handlers.Load(resp.Handle); ok { + var handler interface{} + var ok bool + if handler, ok = client.handlers.Load(resp.Handle); !ok { + // possibly the response arrived faster than the job handler was added to client.handlers, we'll wait a bit and give it another try + time.Sleep(WORK_HANDLE_DELAY_MS * time.Millisecond) + if handler, ok = client.handlers.Load(resp.Handle); !ok { + client.err(errors.New(fmt.Sprintf("unexpected %s response for \"%s\" with no handler", resp.DataType, resp.Handle))) + } + } + if ok { if h, ok := handler.(ResponseHandler); ok { h(resp) } else { client.err(errors.New(fmt.Sprintf("Could not cast handler to ResponseHandler for %v", resp.Handle))) } - } else { - client.err(errors.New(fmt.Sprintf("unexpected %s response for \"%s\" with no handler", resp.DataType, resp.Handle))) } client.responsePool.Put(resp)