Your Queueable and future jobs will all be represented by different AsyncApexJob
records, and enqueuing a future method doesn't yield your calling code a job Id that you can monitor. As a result, when you're trying to monitor the progress of a job that spans multiple types of asynchronous code, you generally have to implement your own "transaction Id" sort of mechanic.
This would be some kind of unique identifier you supply to the first job in the chain, and which is passed to each successive asynchronous piece of code along the way to preserve the identity of the overall process.
One form that this could take is a Custom Object My_Job__c
, a record of which is created at the time of enqueuing the first asynchronous job in the sequence. Each successive async job can then obtain as one of its parameters the Id of that record and can perform an update against it to record the progressive status of the larger job before spawning the next async code in the sequence, passing along the record's Id. Once the status is updated to the final value, you can persist the date of completion to that object.
If your async process has a "fan out" structure, as it sounds like it does with multiple future methods being called from Queueables, you do have to consider carefully the possibility of lock contention against an object like that. (What if two or three future jobs execute in parallel and one or more of them takes a while to run?)
For that reason, among others, I would generally prefer to use (serial) Queueable chaining rather than a fan-out structure that changes between types of asynchrony.
What you might do if, as you mention in comments, you have 10 futures being fired from a single Queueable and you cannot change that architecture, would be to have a persistent job object as described above with a checkbox field for each of the 10 sub-jobs. Have each sub-job take the job object Id as one parameter, make its callout (I presume they're callout jobs), and at the very end query the job object FOR UPDATE
and check off the checkbox field that corresponds to the sub-job. You'll need to keep the duration of that lock as short as you possibly can, because the possibility of lock contention with this architecture is significant.
You could then have a workflow rule/process/trigger on the job object whose entry condition requires that all 10 boxes are checked and a field update action to populate NOW()
into a DateTime field to record the overall completion.
Alternately or in addition, that final piece of automation could fire a Platform Event, which makes it easier for your front-end to listen for job completion without polling the database.