0

The following randomly calls getParentCustomers or getAccountManagers first. When it does it works fine. However, whichever one gets called second passes a null into it. Neither of these methods mutates the incoming values in any way. I am guessing there is something about the context that these are called from that the original pointer to response.salesChannels gets lost between tasks.

Map response = [
    salesChannels:   null,
    accountManagers: null,
    parentCustomers: null,
    isrs:            null,
    operatingUnits:  null,
    businessUnits:   null
]

def t1 = task {
    response.salesChannels = salesChannelApiService.get(salesChannel)

    def t1a = task {
        response.parentCustomers = salesChannelTransformService.getParentCustomers(response.salesChannels)
    }
    def t1b = task {
        response.accountManagers = salesChannelTransformService.getAccountManagers(response.salesChannels)
    }

    waitAll([t1a, t1b])
}

def t2 = task {
    //... other stuff
}

def t3 = task {
    //... other stuff
}

waitAll([t1, t2, t3])

return response

I even tried to modify the internals to leverage onComplete instead.

...
onComplete([task {
    return salesChannelApiService.get(salesChannel)
}], { salesChannels ->
    response.salesChannels = salesChannels

    def t1a = task {
        response.parentCustomers = salesChannelTransformService.getParentCustomers(salesChannels)
    }
    def t1b = task {
        response.accountManagers = salesChannelTransformService.getAccountManagers(salesChannels)
    }

    waitAll([t1a, t1b])
})
...

However, I still end up with the same result.

NOTE: This is random too. Sometimes it works fine - passing the same list to both methods. But when it breaks, it is always whichever one that fires second.

Any thoughts on this?

franzcatch
  • 169
  • 2
  • 15

2 Answers2

0

The below solution is working, for now. However, I have no idea why neither of the above code blocks don't.

Any thoughts?

def t1 = createPromise()

task {
    response.salesChannels = salesChannelApiService.get(salesChannel)

    def t1a = createPromise()
    def t1b = createPromise()

    task {
        response.parentCustomers = salesChannelTransformService.getParentCustomers(response.salesChannels)
        t1a.accept()
    }
    task {
        response.accountManagers = salesChannelTransformService.getAccountManagers(response.salesChannels)
        t1b.accept()
    }

    onComplete([t1a, t1b], { a, b -> t1.accept() })
}
franzcatch
  • 169
  • 2
  • 15
0

So I think threading was acting up a bit on rare occasions, so I removed the separate threads between getParentCustomers and getAccountManagers since they aren't making external calls anyway.

I think using response.salesChannels simultaneously across threads was messing with memory allocation of response.salesChannels - and it was throwing a null pointer exception randomly every few hundred calls.

This seems to be much more reliable.

def t1 = createPromise()

task {
    response.salesChannels = salesChannelApiService.get(salesChannel)

    def t1a = createPromise()

    task {
        response.parentCustomers = salesChannelTransformService.getParentCustomers(response.salesChannels)
        response.accountManagers = salesChannelTransformService.getAccountManagers(response.salesChannels)
        t1a.accept()
    }

    onComplete([t1a], { a -> t1.accept() })
}
franzcatch
  • 169
  • 2
  • 15