cancel
Showing results for 
Search instead for 
Did you mean: 

All requests fail in batch if one fails

mehmetemin
Advisor
Advisor

Hi all,

I have a backend powered by CAP, and have another (express) app where I use cloud sdk to save entries.
As I have lots of entries to save, I do it in batch.
When all goes well, lets say I save 30 entries in one request, then I see all of them in the db.
When one of them fails (i.e., Entity already exist), I was expecting to see 29 of them but I see none.

Interesting thing is, I see CREATE /SituationContextData null log 30 times (in both successful and unsuccessful cases). When I overwrite with the function below

srv.on("CREATE", "SituationContextData", async (req, next) => {
    console.log("I also see this log 30 times")
});

So, Create is called 30 times but it simply does not save any of them even if one of them fails.

I assume this is not the expected behaviour, right? What is the mistake here?

Let me share the client side code as well, this is how I do the request:

// I populate the create requests
const newEntry = SituationContextData.builder()
    .sitndataContextId(situation.SitnDataContextID)
    ...
    .build();
createRequests.push(SituationContextData.requestBuilder().create(newEntry));

// ....
// later I get 30 of them to do a batch request
var someOfTheReqs = createRequests.slice(0, 30);
let updateChangesetResponse = (await batch(changeset(...someOfTheReqs)).execute({destinationName: 'CAPBackend'}));

console.log('updateChangesetResponse: ', updateChangesetResponse);
// let result = (updateChangesetResponse[0] as WriteResponses).responses.map(response => response.as!(SituationContextData));
let result = (updateChangesetResponse[0] as ErrorResponse).body.error ;
console.log('result : ', result);

EDIT (after Sergei's answer):

I was putting all the create request in one chanceset and therefore if one fails all is rollbacked (as expected).
After Sergei's suggestion I changed the piece of code to this:

let updateChangesetResponse = (await batch(...(someOfTheReqs.map(request => changeset(request)))).execute({destinationName: 'CAPBackend'}));

And now the create request is executed untill the first error. For example, if there is an error in the 13th request, then 12 entities are created. However the entities between 14th to 30th are not created (not even tried, so I only see 13 logs for CREATE request)

Now the question is, how I can force executing the rest? Can I?
Is there a configuration, or shall I overwrite the function with srv.on("CREATE",...?

Final question:
Actually, I even started questionizing my strategy. I want to save lots of entities, and I dont mind if one of them fails I still want to save the rest. I thougth I should be using batch for that, but if there is another suggestion I would appreciate that as well.

View Entire Topic
mehmetemin
Advisor
Advisor
0 Kudos

So half of the problem was caused by the wrong usage of the changeset (thanks to Sergei)

So if you want the execution to continue even on error, then you need to specify 'odata.continue-on-error' as a preference (documentation)

So I changed my code as follows, now it issues 30 request regardles of the error, and even if the 14th fails, I can see 29 entities are created

let updateChangesetResponse = await batch(...someOfTheReqs)
    .withCustomHeaders({prefer: 'odata.continue-on-error'})
    .execute({destinationName: 'CAPBackend'});

Note that there is no changeset, and there is a custom header.

PS: If someone thinks that this can be done differently, that there is a better way, please share with us.