1

I'm writing an application where I'm chaining jobs by calling executeBatch for the next job in the finish method of the previous one.

In case a job somewhere in the chain fails, I'd need to rollback the operations of not only the current job, but all the previously completed jobs. I would assume that for the current job, I'd need to initialize a savepoint in the constructor and then if an error occurs, do a rollback in the catch block. But how would I handle the jobs that finished successfully too? Do I initialise a savepoint at the start and pass it along through the chain?

I could also consider initialising a savepoint, serialising it and storing it in the database to retrieve later if needed, but I'm not sure this is possible.

  • As far as I know, Savepoint is valid only in one execution context. Check salesforce.stackexchange.com/questions/93996/… and developer.salesforce.com/docs/atlas.en-us.apexcode.meta/…. It is not being said explicitly, but it says that it is working only for single trigger context, what is smaller than execution context, but I can not find confirmation for that – kurunve Feb 9 '17 at 6:10
  • Wow, that certainly doesn't sound good. Do I have any alternatives? I'm pretty sure I'm not the only person who's come up against this sort of issue... there must be some sort of workaround. – coldspeed Feb 9 '17 at 6:13
  • Well, can you describe your case more precisely? why do you needs to revert so much information? Probably, it would be more sense to mark information as invalid unless entire batch is completed? and as long as that is done -- mark it as valid? – kurunve Feb 9 '17 at 8:05
  • Well, basically, I have a few chained jobs that do some processing on the same set of records. Each job modifies some values which are in turn evaluated by the jobs after it. That's why, it's either an all or nothing situation. – coldspeed Feb 9 '17 at 10:18
  • Can you describe those more precisely? – kurunve Feb 9 '17 at 10:28
2

You cannot rollback the entire batch job since each batch is considered a discrete transaction.

Each execution of a batch Apex job is considered a discrete transaction. For example, a batch Apex job that contains 1,000 records and is executed without the optional scope parameter from Database.executeBatch is considered five transactions of 200 records each. The Apex governor limits are reset for each transaction. If the first transaction succeeds but the second fails, the database updates made in the first transaction are not rolled back.

More info here: https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_batch_interface.htm

References to savepoints cannot cross trigger invocations because each trigger invocation is a new trigger context. If you declare a savepoint as a static variable then try to use it across trigger contexts, you will receive a run-time error.

More on transaction control here: https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/langCon_apex_transaction_control.htm

|improve this answer|||||
  • Okay... since that's established, what are my options? – coldspeed Feb 9 '17 at 6:57
  • An option that comes to mind would be to create your own rollback logic in the finish() method. Maybe you could keep some type of flag to keep track of the records that are being processed and the status of each of them to help identify them. You could either implement Database.Stateful to keep track of any failures in any of the batches or query records the records to see if any have the Failed flag, then roll back the changes yourself. You would need to get a bit creative on how you would do this but I can imagine it would be possible. – Bob Lopez Feb 9 '17 at 16:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.