Closed newcron closed 2 years ago
Hi @newcron, our apologies for the delay in reply. We'll investigate it and get back to shortly.
Hi @newcron, thanks for reaching out!
I checked and I think it can indeed be the case, if the same object is being serialised multiple times at the same time.
The relevant SDK code is probably:
final boolean oldAccessibleValue = propertyField.isAccessible();
propertyField.setAccessible(true);
// this breaks if another thread changes this in the mean time
final Object propertyValue = propertyField.get(value);
propertyField.setAccessible(oldAccessibleValue);
I think we never thought of this case, since typically an object is only sent once to a service, at least at a specific point same time. Can you confirm that this is realistic in your use case? If not, we might have to look further than that..
But of course, this looks like a race condition we need to fix in any case. We'll get back to you with an estimation when a fix will be available.
Yes, I do think it's relevant. I our case, we're updating many prices in parallell.
It's not the same instanceof SlsPrcgConditionRecord
but for the reflection code you're showing above, you're not working on the object instances, but on the Class
object, that all of these instances share.
In that sense, I would argue that indeed there is a good use case to fix thread safetiness on that. Also keep in mind, that when the SAP cloud sdk is used in the context of a web application, there's also a realistic chance of concurrent requests.
Hi @newcron,
While we are comparing different solution to the race condition, I would like to enable you with a workaround until we're done (and released).
I think the current issue boils down to the fact that the parallel threads use the same underlying Gson
object. This results into the same ODataVdmEntityAdapterFactory
instance being reused in a concurrent environment. The class maintains a collection of stateful java.lang.reflect.Field
objects, for which we change accessibility flags. And that leads to the observed race condition.
You could avoid / workaround the problem by making sure every outgoing request has it's own Gson
instance in use for JSON serialization. Unfortunately we don't have public API to enable this conveniently. This is why I would now suggest the usage of our Generic OData Client to unblock you:
final SlsPrcgConditionRecord record;
// static data
final String servicePath = SalesPricingConditionRecordService.DEFAULT_SERVICE_PATH;
final String entityCollection = "???" /* LOOK UP VALUE FROM SlsPrcgConditionRecord#getEntityCollection */
// dynamically invoke for every session, alternatively for every outbound request
final HttpClient httpClient = HttpClientAccessor.getHttpClient(sapEndpoint.destination);
// dynamically invoke for every outbound request
final Gson gson = new GsonBuilder().create();
final String payload = gson.toJson(record);
final ODataResourcePath resourcePath = ODataResourcePath.of(entityCollection);
final ODataRequestCreate request = new ODataRequestCreate(servicePath, resourcePath, payload, ODataProtocol.V2);
request.execute(httpClient); // response can be evaluated if necessary
Please let me know if it works for you.
Update: A fix for this has been shipped with Cloud SDK Version 3.59.0.
Issue Description
I am synchronizing prices between an external system and SAP HANA Cloud using the client.
As there is a big number of prices to be synched, these syncs are running asynchronousely in a thread pool. I found that some of the requests fail with the below exception leading to data inconsistency issues. Seems to me that there might be an issue with thread safetiness
The exceptions are shown below.
Code looks like this:
Impact / Priority
Risk of data inconsistency between prices across systems. This could cause legal liabilities or financial losses for us.
Error Message
Dependency Tree:
Project Details
confidential
Checklist