0

We are making a rest API call to the external DB. In simplified terms, it looks like below (the payload might not be in the correct json format here but normally it is).

public class UpdateExternalDBQueueable implements Queueable, Database.AllowsCallouts {
    private List<Id> offerIds;

    public UpdateExternalDBQueueable(List<Id> offerIds) {
        this.offerIds = offerId;
    }

    public void execute(QueueableContext context) {
        List<Offer__c> updatedOffers = [SELECT Expiration_Date__c, Web_Id__c FROM Offer__c WHERE Id IN :offerIds];

        String payload;
        for (Offer__c offer: offers) {
            OfferUpdateRequestModel offerUpdateRequest = new OfferUpdateRequestModel();
            offerUpdateRequest.webId = offer.Web_Id__c;
            offerUpdateRequest.offerExpirationDate = offer.Expiration_Date__c;

            payload += JSON.serialize(offerUpdateRequest, false);
        }

        // then make the rest call 
    }
}
    

And we call this queueable from some other class like below.

public class OfferUpdateAction {
    @InvocableMethod(label='Update offer expiration')
    public static void init(List<Id> offerIds) {

        List<Offer__c> offers = [SELECT Offer_Expiration_Date__c FROM Offer__c WHERE Id IN :offerIds];
        for (Offer__c offer : offers) {
            offer.Offer_Expiration_Date__c = DateTime.now().addDays(1);
        }
        update offers;

        System.enqueue(new UpdateExternalDBQueueable(offerIds));
    }
}

Since the queueable doesn't make any modification and just makes a callout with the provided data, I can send a list of objects and get rid of the SOQL in the queueable.

But making that breaks the single responsibility* for the caller class. If I need to send another field to the API, I need to change Queueable and the caller instead of just the queueable since the SOQL is in the caller in the new version.

Which one to choose in a situation like this? Or in general, what things should be considered when making a choice?

(Edit: After writing this, it occurred to me that probably the better solution would be moving queueable call into the trigger so after the expiration date changes, it can be called from there with trigger.new list but still, want to see your thoughts)

*: A class should have only one reason to change

1 Answer 1

3

This is opinion based, so take your own view.

For me, the only robust state you have available to you within Salesforce is that held in an SOQL accessible manner in the Salesforce database. Having queueables or other async processes that rely on provided state is potentially fragile - if the async process dies due to some uncatchable governor limit issue you may not be able to recover since the state will be lost (the Transaction Finalizer helps here for state-based queueables, of course).

Regardless, marking data in the database for action by some async processing is far more robust (IMHO) as long as the setting and clearing of that mark is in itself robustly addressed (you may want to have specific objects for handling this rather than marking the actual object records in case someone sloppily adds a validation rule that prevents the marking being updated against what might otherwise be a badly configured record that fails this validation, for example).

As to a single responsibility, the actual querying of data can be shunted to a separate class, e.g. using the Selector pattern.

Not the answer you're looking for? Browse other questions tagged .