We have a springboot/sap-cloud-sdk (3.34.1) application deployed on SAP CloudFoundry. Our application connect to an on-prem SAP Gateway for OData services and uses the CF destination and connectivity service. In most cases this works ok. We recently started using batch requests towards our SAP OData service.
Local testing against the SAP gateway shows that the batch requests are handled fine. We get the proper error results when we send an request that should fail and when we send a good request it's also handled fine.
However when we deploy the application on SAP CF, and the request is routed through the connectivity service we always get a HTTP 202 Accepted response. No matter what the SAP Gateway returns. If we do some debugging and tracing on the SAP Gateway, we see the expected requests coming in and also see the expected responses from the SAP Gateway.
So it seems that the connectivity service somehow is unable to pass the responses back to our application.
The picture above shows the components the request pass through. Our PMD App uses the cloud sdk to create the batch requests, resolved the destination and send it, throught the connectivity service, to the SAP Gateway. The gateway returns the proper response, but we never see that response in our app. Instead we always get a 202 Accepted response.
-- Update 2020-12-15 16:39 --
We're using OData V2. We've done some more testing and it's not the connectivity service. We've only been focusing on the response payloads of the SAP Gateway. But apparently the batch responses are always wrapped in a 202 Accepted response. If we look more closely, than we see that we get the following response:
HTTP/1.1 202 Accepted
content-type: multipart/mixed; boundary=6C34B07793A6EA7C8AAFC5BC339BDAEC0
content-length: 709
dataserviceversion: 2.0
cache-control: no-cache, no-store, must-revalidate
sap-perf-fesrec: 1300458.000000
--6C34B07793A6EA7C8AAFC5BC339BDAEC0
Content-Type: application/http
Content-Length: 1171
content-transfer-encoding: binary
HTTP/1.1 400 Bad Request
Content-Type: application/json;charset=utf-8
Content-Length: 1050
dataserviceversion: 1.0
{"error":{"code":"ZCU/100","message":{"lang":"nl","value":"Service 0000000003 0000000010 niet gevonden voor operatie 0410"},"innererror":{"application":{"component_id":"","service_namespace":"/SAP/","service_id":"ZCU_PE_ORDER_SRV","service_version":"0001"},"transactionid":"23F2932D54040110E005FD84A23B406E","timestamp":"20201215151501.0634490","Error_Resolution":{"SAP_Transaction":"Run transaction /IWFND/ERROR_LOG on SAP Gateway hub system (System Alias ) and search for entries with the timestamp above for more details","SAP_Note":"See SAP Note 1797736 for error analysis (https://service.sap.com/sap/support/notes/1797736)","Batch_SAP_Note":"See SAP Note 1869434 for details about working with $batch (https://service.sap.com/sap/support/notes/1869434)"},"errordetails":[{"code":"ZCU/100","message":"Service 0000000003 0000000010 niet gevonden voor operatie 0410","propertyref":"","severity":"error","target":""},{"code":"/IWBEP/CX_MGW_BUSI_EXCEPTION","message":"Fout bij wijzigen PE order.","propertyref":"","severity":"error","target":""}]}}}
--6C34B07793A6EA7C8AAFC5BC339BDAEC0--
And somehow the content of the response is not read properly by the SAP Cloud SDK.
In our code we send 1 changeset with the request. The following methods are the core of our batch call. The batchUpdatePEOrderById
executes the request. The other methods are just helpers to prepare the batch request.
We expected f.get(0)
would unwrap the results of the first changeset, or at least in our example request would result in a Try.failure(), but it always results in a Try.success()
private Either<DomainError, ExternalId> batchUpdatePEOrderById(final ExternalId id, List<ServiceChange> serviceChanges, final String jwtToken) {
final HttpDestination sapMatrix = httpDestinationProvider.providePrincipalPropagationDestination(jwtToken);
// See https://sap.github.io/cloud-sdk/docs/java/features/odata/use-typed-odata-v2-client-in-sap-cloud-sdk-for-java#batch-requests
var f = prepareBatchRequest(id, serviceChanges)
.executeRequest(sapMatrix);
return f.get(0).toEither()
.bimap(error -> getDomainError(id, error), result -> {
log.warn("Updated PE-Order {} successfully: {}", id, result.getCreatedEntities());
return id;
});
}
private ZCUPEORDERSRVServiceBatch prepareBatchRequest(ExternalId id, List<ServiceChange> serviceChanges) {
var batch = peOrderService.batch();
var changeSet = batch.beginChangeSet();
// Split service changes and add to batch operation
var newServices = mapServiceChanges(ChangeType.ADDED, serviceChanges, id);
var updatedServices = mapServiceChanges(ChangeType.QUANTITY_CHANGED, serviceChanges, id);
var deletedServices = mapServiceChanges(ChangeType.DELETED, serviceChanges, id);
if (!newServices.isEmpty()) {
buildServiceChangeSet(changeSet, newServices, ChangeType.ADDED);
}
if (!updatedServices.isEmpty()) {
buildServiceChangeSet(changeSet, updatedServices, ChangeType.QUANTITY_CHANGED);
}
if (!deletedServices.isEmpty()) {
buildServiceChangeSet(changeSet, deletedServices, ChangeType.DELETED);
}
return changeSet.endChangeSet();
}
private void buildServiceChangeSet(ZCUPEORDERSRVServiceBatchChangeSet changeSet, final List<Dienst> services, final ChangeType changeType) {
switch (changeType) {
case ADDED:
services.forEach(changeSet::createDienst);
break;
case QUANTITY_CHANGED:
services.forEach(changeSet::updateDienst);
break;
case DELETED:
services.forEach(changeSet::deleteDienst);
break;
default:
changeSet.endChangeSet();
}
}
Any ideas what could be wrong here?
Thanks,
Danny
This bug is fixed as of SAP Cloud SDK
3.34.1
.Check out the respective release notes.