Run more than one async jobs from Future/Quable context
To add on to Phil's answer, what I do before ever invoking a future or a queuable is to reference these utility properties:
public static Boolean isFutureable {
get {
if (isFutureable != null) {return isFutureable;} // for testing, permits coercion of value
if (System.isFuture()) {return false;} // no future permitted from future
if (System.isBatch()) {return false;} // no future permitted from batch
return Limits.getLimitFutureCalls() - Limits.getFutureCalls() > 0; // adequate headroom
}
set;
}
public static Boolean isEnqueueable {
get {
return isEnqueueable == null ? Limits.getLimitQueueableJobs() - Limits.getQueueableJobs() > 0 : isEnqueueable;}
set;
}
Why properties and not methods? So testmethods can coerce a value in order to test out various paths
So,
if (Util.isFutureable) {..call @future method..}
else {
if (Util.isEnqueueable) { .. System.enqueueJob(..); ...}
else {
System.schedule(...) // some fallback job to get us going again
// (although should also check for limits here too)
}
I won't try to go in Future/Queueable chains, it can get messy.,
What I would do is to break the chain.
Your requirement of
save to BigObect
can be done by just firing a platform event. Inside the platform event trigger you can save it to the big objects,
We use platform events and big objects to log things, so I am sure about this approach. What platform event gives you is the flexibility to retry.
This limitation specifically applies to future methods:
No more than 0 in batch and future contexts; 1 in queueable context method calls per Apex invocation
The solution is to make the initial invocation use a Queueable rather than a future method and to break chains of queuables/futures by alternating the approach if at all possible.
In terms of checking things twice, that should be OK as long as you have a common piece of code used in both contexts.