How can I cause side effects outside an execution context?

I’ve got a scenario that relies on the system’s “automatic rollback” behaviour to undo any DML, emails, futures and so on, in the case of an error. Basically, by allowing code to throw an unhandled exception in a batch execute, I guarantee almost everything gets rolled back. Pretty hair brained!

Except there’s this one little thing I do want to survive. The e.getMessage() string.

So I’ve been trying to think of mechanisms for doing this. I had a couple of angles:

  • querying AsyncApexJob.ExtendedStatus (can’t see anything but the first exception),
  • use an HttpRequest callout to do something with message (can’t after DML or savepoint)
  • try Page.getContent() on a VF page with an action attribute (can’t do this in batch)
  • courtesy crop1645, pull it the Apex Exception email notification (can’t do this from inside org)

Is there any other “last ditch” measure I can use to have side effects outside the transaction?

I need only to get my paws on that error string. Or stick it somewhere so another context can!

Edit: they published it 🙂
https://success.salesforce.com/issues_view?id=a1p300000008Y1OAAU

Answer

Update, Summer ’17:

Platform Events are now GA. Note the following from the docs:

Platform Events and Transactions
Unlike custom objects, platform events aren’t processed within database transactions in the Force.com platform. As a result, publishing platform events can’t be rolled back. Note the following:

  • The allOrNoneHeader API header is ignored when publishing platform events through the API.
  • The Apex setSavepoint() and rollback() Database methods aren’t supported with platform events.

So you could publish an event with the required information and have a corresponding Apex trigger subscribed to the event to store the persistent message.

I’ve expanded the idea out a bit in Can I store information even if the trigger throws an exception?


Wrap the contents of the batch execute method in a try catch and for any caught exceptions throw a new exception with the most important information at the start of the message property. Ideally this will show up in the AsyncApexJob.ExtendedStatus.

This will only help if the exception is of a type that can be caught.


You could abuse the logging mechanism. Use a scheduled task to keep a TraceFlag active for the user running the batch job.

In the Batch finish method pull the log contents if NumberOfErrors is greater than zero. Then painfully extract the missing information.

You could potentially combine this with the above approach and a System.debug(LoggingLevel.Error, e.getMessage()).


Better yet, use a Checkpoint in the code to capture the contents of the exception. Then extract the Exception message from the ApexExecutionOverlayResult using the ToolingAPI from Apex.

Attribution
Source : Link , Question Author : Matt and Neil , Answer Author : Daniel Ballinger

Leave a Comment