Triggered email appears to be sending 2 emails to each contact intermittently

I have a triggered email associated with an overnight job, It checks to see if a report has been emailed out then looks for contacts who have signed up for the report and then sends the report to each of the contacts. It is an intermittent issue in that some days the test group gets 1 email other days 2 recieved at the same time anyone have any insight as to why this could be happening?

export async function sendEmailToContact() {
    let contactId = [];
    let options;
    const triggeredEmailTemplate = '*******';
//Has email been sent if not then send email
        const emailinfo = await wixData.query("emailreports").eq("title", 'principal_Changes').limit(100).find();
    if (emailinfo.items[0].emailsent === "false") {
// Get Contacts
        const queryResults = await contacts.queryContacts()
            .eq('info.extendedFields.custom.principlereport', "Yes")
            .find();
        const contactsWithEmail = queryResults.items;
        if (contactsWithEmail.length === 1) {
            console.log('Found 1 contact');
            contactId[0] = contactsWithEmail[0]._id;
        } else if (contactsWithEmail.length > 1) {
            // Handle when more than one contact is found
            console.log('Found more than 1 contact');
            for (let i = 0; i < contactsWithEmail.length; i++) {
                contactId[i] = contactsWithEmail[i]._id;
            }
        } else {
            console.log('No contacts found');
            // Handle when no contacts are found
        }
 // Get variables to post to email template
        const principleresults = await wixData.query("principles").gt('amount_change', 0).limit(100).descending('amount_change').ascending('frn').find();
        if (principleresults.items.length > 0) {
            let item = principleresults.items;
            let totalCount = principleresults.length;
        }
        let resultsdate = (principleresults.items[0]._updatedDate).toLocaleDateString()
        let represults = await wixData.aggregate("principles")
            .sum("amount_change")
            .run()
        options = {
            variables: {
                NoPrinciples: principleresults.totalCount,
                NoReps: represults.items[0].amount_changeSum,
                Principle1: principleresults.items[0].organisationName,
                Principle1Ars: principleresults.items[0].amount_change,
                Querydate: resultsdate
            }
        }
        console.log('Send email')
        // Flag sent email table
        let toUpdate = {
            "_id": emailinfo.items[0]._id,
            "emailsent": "true",
            "title": "principal_Changes"
        };
        try {
            let results = await wixData.update("emailreports", toUpdate)
            console.log(results); //see item below
        } catch (err) {
            console.log(err);
        }
        // Send report to all who have it as Yes
        for (let j = 0; j < contactId.length; j++) {
            try {
                await triggeredEmails.emailContact(triggeredEmailTemplate, contactId[j], options);
                console.log('Email sent to contact ' + contactId[j]);
            } catch (error) {
                console.error(error);
                // Handle the error
            }
        }
    } else { console.log('Email Already sent') }
}

Can you confirm if the “emailreports” Data Collection has emails more than once in the collection? If so you can tack on .distinct() as described here. https://www.wix.com/velo/reference/wix-data/wixdataquery/distinct

Let us know if that works.

Its a single row collection currently as we are just setting up the reports so only 1 record / row in total.
Also of interest the Statistics for it show that 2 emails where sent on the 12th, 1 to each contact it was supposed to. My inbox recieved 2 this morning as did the other test email.

Edit: See above comment re schduler pls

Worked out why this is happening and the code above is fine. The issue is with the scheduled jobs, it appears to be running twice within 0.5s

the jobs.config is using cron expressions all set out to run at diffrent minutes past the hour so not the reason for the above. Any suggestions welcome.

Can you share your jobs.config? It might help in debugging this.

Here is the old jobs.config, I updated it by changing a function name, now in the site events i see both the old (whichbatchjob) function call and new (stopdoubleruns) functions being called. I guess this would imply that I have a ghost file that I cant see but is being used. I moved the timeings slightly on the update to avoid running at the same time and basically have 40 scheduled jobs now.

{
  "jobs": [
    {
      "functionLocation": "/overnight.jsw",
      "functionName": "whichbatchjob",
      "description": "Time based fun to decide which batch job to run",
      "executionConfig": {
        "cronExpression": "57 * * * *"
      }
    },
    {
      "functionLocation": "/overnight.jsw",
      "functionName": "whichbatchjob",
      "description": "Time based fun to decide which batch job to run",
      "executionConfig": {
        "cronExpression": "54 * * * *"
      }
    },
    {
      "functionLocation": "/overnight.jsw",
      "functionName": "whichbatchjob",
      "description": "Time based fun to decide which batch job to run",
      "executionConfig": {
        "cronExpression": "51 * * * *"
      }
    },
    {
      "functionLocation": "/overnight.jsw",
      "functionName": "whichbatchjob",
      "description": "Time based fun to decide which batch job to run",
      "executionConfig": {
        "cronExpression": "48 * * * *"
      }
    },
    {
      "functionLocation": "/overnight.jsw",
      "functionName": "whichbatchjob",
      "description": "Time based fun to decide which batch job to run",
      "executionConfig": {
        "cronExpression": "45 * * * *"
      }
    },
    {
      "functionLocation": "/overnight.jsw",
      "functionName": "whichbatchjob",
      "description": "Time based fun to decide which batch job to run",
      "executionConfig": {
        "cronExpression": "42 * * * *"
      }
    },
    {
      "functionLocation": "/overnight.jsw",
      "functionName": "whichbatchjob",
      "description": "Time based fun to decide which batch job to run",
      "executionConfig": {
        "cronExpression": "39 * * * *"
      }
    },
    {
      "functionLocation": "/overnight.jsw",
      "functionName": "whichbatchjob",
      "description": "Time based fun to decide which batch job to run",
      "executionConfig": {
        "cronExpression": "36 * * * *"
      }
    },
    {
      "functionLocation": "/overnight.jsw",
      "functionName": "whichbatchjob",
      "description": "Time based fun to decide which batch job to run",
      "executionConfig": {
        "cronExpression": "33 * * * *"
      }
    },
    {
      "functionLocation": "/overnight.jsw",
      "functionName": "whichbatchjob",
      "description": "Time based fun to decide which batch job to run",
      "executionConfig": {
        "cronExpression": "30 * * * *"
      }
    },
    {
      "functionLocation": "/overnight.jsw",
      "functionName": "whichbatchjob",
      "description": "Time based fun to decide which batch job to run",
      "executionConfig": {
        "cronExpression": "27 * * * *"
      }
    },
    {
      "functionLocation": "/overnight.jsw",
      "functionName": "whichbatchjob",
      "description": "Time based fun to decide which batch job to run",
      "executionConfig": {
        "cronExpression": "24 * * * *"
      }
    },
    {
      "functionLocation": "/overnight.jsw",
      "functionName": "whichbatchjob",
      "description": "Time based fun to decide which batch job to run",
      "executionConfig": {
        "cronExpression": "21 * * * *"
      }
    },
    {
      "functionLocation": "/overnight.jsw",
      "functionName": "whichbatchjob",
      "description": "Time based fun to decide which batch job to run",
      "executionConfig": {
        "cronExpression": "18 * * * *"
      }
    },
    {
      "functionLocation": "/overnight.jsw",
      "functionName": "whichbatchjob",
      "description": "Time based fun to decide which batch job to run",
      "executionConfig": {
        "cronExpression": "15 * * * *"
      }
    },
    {
      "functionLocation": "/overnight.jsw",
      "functionName": "whichbatchjob",
      "description": "Time based fun to decide which batch job to run",
      "executionConfig": {
        "cronExpression": "12 * * * *"
      }
    },
    {
      "functionLocation": "/overnight.jsw",
      "functionName": "whichbatchjob",
      "description": "Time based fun to decide which batch job to run",
      "executionConfig": {
        "cronExpression": "9 * * * *"
      }
    },
    {
      "functionLocation": "/overnight.jsw",
      "functionName": "whichbatchjob",
      "description": "Time based fun to decide which batch job to run",
      "executionConfig": {
        "cronExpression": "6 * * * *"
      }
    },
    {
      "functionLocation": "/overnight.jsw",
      "functionName": "whichbatchjob",
      "description": "Time based fun to decide which batch job to run",
      "executionConfig": {
        "cronExpression": "3 * * * *"
      }
    },
    {
      "functionLocation": "/overnight.jsw",
      "functionName": "newFrnOvernight",
      "description": "Overnight New FRN for New List",
      "executionConfig": {
        "cronExpression": "00 19 * * *"
      }
    }
  ]
}

I see. So the issue here is that jobs cannot run every 3 minutes within jobs.config. They can at most run every hour: https://support.wix.com/en/article/velo-scheduling-recurring-jobs#cronexpression-string

While the workaround here may appear valid it’s running into issues because it’s working around an intentional limitation of jobs.config. There’s probably a timing issue caused by this workaround leading to the same function running twice at around the same time.

As for the old/new jobs I would give it a day and see if that disappears. I have a sense this is also a delay/timing issue. If not then let me know.

Will let you know if the rogue schedule jobs go over the next few days. The cron jobs are set up to run at those minutes past every hour and are working perfectly so no issue theie its more that I have been seeing overlaping jobs due to the duplicate / ghost jobs.config file that I cant see.

Thanks, can you provide the metaSiteId for the website you’re having this issue with? You’ll find it as one of the query parameters in the URL for your editor (or you can just share the whole editor url)

f8853fc1-ab40-4ef1-971b-345880f34f9a.
Issue has got a little worse from a jobs call perspective it now runs 3 times in 1 second but I have renamed the some functions so now all it does is post a console.log message. I have also logged with CS

Gotcha, it’s been escalated so someone is taking a look.