I was facing a similar issue and created a little framework that served me well on various projects. See Github: salesforce-apex-retry.
Although not my intended use-case you could simply achieve the desired behavior with the added benefit of automatic rescheduling of the call-outs in case of failure. With these classes and custom object installed you could easily do the following:
global void execute(Database.BatchableContext BC, List<Object> scope) {
List<CustomObject> customObjects; //here build a list of custom object;
insert customObjects;
List<RetryableJob__c> futureJobs = new List<RetryableJob__c>();
for (CustomObject customObject : customObjects) {
Id customObjectId = customObject.Id;
Retryable job = new RetryableCallout(customObjectId);
futureJobs.add(new RetryableJob__c(
status__c = Retryable.Status.FAILED_RETRY.name(),
nextTry__c = System.now(),
lastTry__c = System.now(),
serializedJob__c = JSON.serialize(job),
count__c = 0,
message__c = 'INSERTED IN BATCH',
className__c = String.valueOf(job).split(':')[0]
));
}
insert futureJobs;
}
And your RetryableCallout class would extend Retryable and look like this:
public class RetryableCallout extends Retryable {
private Id customObjectId;
public void RetryableCallout(Id customObjectId){
this.customObjectId = customObjectId;
}
protected override JobResult startJob() {
CustomObject__c customObject = [
SELECT Id, Name, Customfield__c
FROM CustomObject__c
WHERE Id = : this.customObjectId
];
HttpRequest request = new HttpRequest();
request.setEndpoint('callout:YOUR_SERVICE_ENDPOINT');
request.setMethod('POST');
request.setHeader('Content-Type', 'application/json');
request.setHeader('Accept', 'application/json');
request.setBody('{"CustomObjectId": "' + customObjectId + '"}');
HttpResponse response = http.send(request);
Integer httpResponseCode = response.getStatusCode();
switch on httpResponseCode{
when 200,201{
return JobResult.success(response.getBody());
}
when 401{
return JobResult.actionRequired(response.getBody());
}
when else {
return JobResult.retry(response.getBody());
}
}
}
}