0

I have the below invocable class which is fired by a Process in PB. It's in my sandbox on a delay of 2 mins after Email Message creation.

When a single email arrives, it works fine. But if two or more arrive in quick succession, it only fires for the first record and ignores the rest and I cannot figure out why. Are there any restrictions on how many processes can fire at once? Is there anything else why it would ignore the following records?

public class jwOrderAttachmentInvocable {
    @InvocableMethod
    public static void jwOrderPDFCloning(List < EmailMessage > emails) {

        Set < String > CaseIds = new Set < String > ();
        Set < String > OrdIds = new Set < String > ();
        //Set<String> MessageIds = new Set<String>();

        for (EmailMessage email: emails) {

            CaseIds.add(email.ParentId);
            //MessageIds.add(email.Id);

            System.debug('The CaseId is ' + email.ParentId);
            system.debug('The MessageId is ' + email.Id);
            //system.debug('The MessageIds Set is '+MessageIds);



            if (!CaseIds.isEmpty()) {

                // find the Opportunity to which the Case relates
                Case op = [Select Id, PDF_Order_Number__c from Case where Id in: CaseIds]; {
                    if (op.PDF_Order_Number__c != null) {
                        OrdIds.add(op.PDF_Order_Number__c + '%');
                    }
                }
                if (!OrdIds.isEmpty()) {


                    Set < String > OrdId = new Set < String > ();
                    Order ord = [Select Id From Order Where ERP_Order_Number__c like: OrdIds ORDER BY LastModifiedDate DESC NULLS LAST LIMIT 1]; {
                        OrdId.add(ord.Id);
                    }
                    System.debug('The OrderId is' + ' ' + ord.Id);
                    if (!OrdId.isEmpty()) {

                        List < Attachment > existing = [Select Id, ParentId, NAme, OwnerId, Body from Attachment where ParentId =: email.Id];
                        system.debug('existing.size - ' + existing.size());

                        if (!existing.IsEmpty()) {

                            Map < String, Attachment > MapOrderRefToId = new Map < String, Attachment > ();

                            for (Attachment att: existing) {
                                MapOrderRefToId.putAll(existing);
                                Integer attsize = MapOrderRefToId.size();
                                system.debug('The Map size is ' + attsize);
                                system.debug('MapOrderRefToId keyset = ' + MapOrderRefToId.keySet());
                                system.debug('MapOrderRefToId values = ' + MapOrderRefToId.values());
                            }
                            List < ContentVersion > cvs = new List < ContentVersion > ();
                            for (Attachment e: existing) {
                                if (MapOrderRefToId.ContainsKey(e.Id)) {

                                    ContentVersion cv = new ContentVersion();
                                    cv.ContentLocation = 'S';
                                    cv.PathOnClient = MapOrderRefToId.get(e.Id).Name;
                                    cv.Origin = 'H';
                                    cv.OwnerId = MapOrderRefToId.get(e.Id).OwnerId;
                                    cv.Title = MapOrderRefToId.get(e.Id).Name;
                                    cv.VersionData = MapOrderRefToId.get(e.Id).Body;
                                    cvs.add(cv);
                                }
                                Database.SaveResult[] cvlist = Database.insert(cvs, false);

                                Set < Id > convsId = new Set < Id > ();

                                for (Database.SaveResult conv: cvlist) {
                                    if (conv.IsSuccess()) {
                                        convsId.add(conv.getId());
                                        System.debug('Successfully inserted Content Version. CV ID: ' + conv.getId());
                                    }

                                    List < ContentVersion > ConVerList = [Select Id, ContentDocumentId from ContentVersion WHERE Id =: convsId];
                                    List < ContentDocumentLink > cdList = new List < ContentDocumentLink > ();
                                    for (ContentVersion con: ConVerList) {
                                        ContentDocumentLink cd = new ContentDocumentLink();
                                        cd.LinkedEntityId = ord.Id;
                                        cd.ContentDocumentId = [SELECT ContentDocumentId FROM ContentVersion WHERE Id in: ConVerList].ContentDocumentId;
                                        cd.ShareType = 'V';
                                        cd.Visibility = 'AllUsers';
                                        cdList.add(cd);
                                        insert cdList;
                                    }
                                }
                            }
                        }
                        //List < Case > Casestodelete = [Select Id from Case where Id in: CaseIds];
                        //delete Casestodelete;
                    }
                }
            }
        }
    }
}
3

Your code's messy indentation and brace style made it hard to follow the logical flow. I ran it through a Java formatter and updated your question with the results.

This helps to illuminate an issue that I suspect is at least contributing to your problem, and may be the actual cause.

    for (EmailMessage email: emails) {

        CaseIds.add(email.ParentId);
        //MessageIds.add(email.Id);

        System.debug('The CaseId is ' + email.ParentId);
        system.debug('The MessageId is ' + email.Id);
        //system.debug('The MessageIds Set is '+MessageIds);

The closing brace for your for loop should be right here. It's not, so instead your nice bulkified code below is run once for each EmailMessage in scope. However, your variables aren't reset, so CaseIds will continue to accumulate values.

        if (!CaseIds.isEmpty()) {

            // find the Opportunity to which the Case relates
            Case op = [Select Id, PDF_Order_Number__c from Case where Id in: CaseIds]; {
                if (op.PDF_Order_Number__c != null) {
                    OrdIds.add(op.PDF_Order_Number__c + '%');
                }
            }

This looks like it was meant to be another for loop, but it's not - it's a single-sObject SOQL query.

I suspect that what happens on your second and subsequent loop iterations is that CaseIds has more than one value in it, and a QueryException is thrown here, terminating the process. It appears to me that you should change this to a for loop to achieve what you want to do.

Because you are running scheduled actions, you should read Transactions and Scheduled Actions. I think it is very likely that your scheduled actions on emails that come in close succession are being grouped and executed in a single transaction.

  • Hi David, Thanks for the formatting help. There has been a secondary issue with accumulating multiple Ids but I'd solved that by ignoring the MessagesIds Set as it was here that was collecting multiples. Whether this is the right thing to do, I don't know. What I can't for the life of me figure out is that if the process is supposed to fire on Email creation, it only does so for the first email when created in quick succession. I'm not sure if PB will automatically scoop up any other records which are meeting the same criteria; I'd always assumed they run on separate threads. – CaptainHaZ Sep 13 '18 at 16:12

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.