iATSPayments / com.iatspayments.civicrm

CiviCRM Extension supporting iATS Payments services
Other
14 stars 38 forks source link

Duplicate recurring contributions - "Failure, Error message: Expected one Contribution but found 0" #258

Open cmmadmin opened 6 years ago

cmmadmin commented 6 years ago

CiviCRM 5.3.1 iATSPayments 1.6.2 Drupal 7.59

We have discovered that 59 recurring contributions were processed twice. They were processed on 09/04/2018 and then again on 09/05/2018. Is this an issue in the payment processor or with iATS?

NOTE: All recurring contributions have run correctly since then (09/06 to 09/10).

On the first day, 09/04/2018, these 59 contributions were processed by iATS but we do not have a record that they ran in CiviCRM except the Schedule Jobs log shows the error "Failure, Error message: Expected one Contribution but found 0" as show below:

2018-09-04 02:30:02
Entity: Job Action: iatsrecurringcontributions
Summary
Starting execution of iATS Payments Recurring Contributions
Details

Parameters raw (From cron.php): 
a:1:{s:7:"version";i:3;}

Parameters parsed (and passed to API method): 
a:1:{s:7:"version";i:3;}

Full message: 
Starting execution of iATS Payments Recurring Contributions

2018-09-04 02:31:26
Entity: Job Action: iatsrecurringcontributions
Summary
Finished execution of iATS Payments Recurring Contributions with result: Failure, Error message: Expected one Contribution but found 0
Details

Parameters raw (From cron.php): 
a:1:{s:7:"version";i:3;}

Parameters parsed (and passed to API method): 
a:1:{s:7:"version";i:3;}

Full message: 
Finished execution of iATS Payments Recurring Contributions with result: Failure, Error message: Expected one Contribution but found 0

On the second day, 09/05/2018, there were 277 recurring contributions processed, including the 59 contributions that ran the previous day. Schedule Jobs log looked normals as follows:

2018-09-05 02:30:02
Entity: Job Action: iatsrecurringcontributions
Summary
Starting execution of iATS Payments Recurring Contributions
Details

Parameters raw (From cron.php): 
a:1:{s:7:"version";i:3;}

Parameters parsed (and passed to API method): 
a:1:{s:7:"version";i:3;}

Full message: 
Starting execution of iATS Payments Recurring Contributions

2018-09-05 02:36:00
Entity: Job Action: iatsrecurringcontributions
Summary
Finished execution of iATS Payments Recurring Contributions with result: Success (277 contribution record(s) were processed.
Successfully processed pending recurring contribution in series id 5154: OK: 555555
Created activity (...)
Details

Parameters raw (From cron.php): 
a:1:{s:7:"version";i:3;}

Parameters parsed (and passed to API method): 
a:1:{s:7:"version";i:3;}

Full message: 
Finished execution of iATS Payments Recurring Contributions with result: Success (277 contribution record(s) were processed.
Successfully processed pending recurring contribution in series id 5154: OK: 555555
Created activity record for contact id 126991
...
adixon commented 6 years ago

The duplicates were due to an incomplete processing on the first of the duplicates. The message "Expected one Contribution but found 0" is likely from the followup processing that the iats extension does after recording a contribution. If the issue hasn't recurred, the it's likely some transient server-related issue of the day.

cmmadmin commented 5 years ago

@adixon This issue has happened to us again on 1/7/2019. We had 46 transactions that were duplicated (processed twice by iATS). All of these transactions were scheduled to run on 1/7 in Civi, however, when the Chron job ran it gave Error message: "Expected one Contribution but found 0". These transactions were included in the Chron job again on 1/8 and were processed in iATS again. Payments for these transactions were processed twice by iATS. This also happened to us on Sep 11 as noted above. This is a serious issue because have to reach out to our donors and apologize for charging them twice.

Can something be implemented to ensure there is a fail-safe handshake that ensures this type of duplication processing will not occur?

Error details from schedule job and Civi log are below.

We would really appreciate a solution to this issue. -Malachi

At 2019-01-07 02:31:30 the iATS Payments Recurring Contributions scheduled job finished with this error:

"Finished execution of iATS Payments Recurring Contributions with result: Failure, Error message: Expected one Contribution but found 0"

Civi Log shows these errors:

Jan 07 02:30:03 [info] $Fatal Error Details = Array ( [callback] => Array ( [0] => CRM_Core_Error [1] => exceptionHandler )

[code] => -1
[message] => DB Error: unknown error
[mode] => 16
[debug_info] => 
    DELETE gc
    FROM civicrm_group_contact_cache gc
    INNER JOIN civicrm_group g ON g.id = gc.group_id
    WHERE g.cache_date <= '20190107023003'
   [nativecode=1213 ** Deadlock found when trying to get lock; try restarting transaction]
[type] => DB_Error
[user_info] => 
    DELETE gc
    FROM civicrm_group_contact_cache gc
    INNER JOIN civicrm_group g ON g.id = gc.group_id
    WHERE g.cache_date <= '20190107023003'
   [nativecode=1213 ** Deadlock found when trying to get lock; try restarting transaction]
[to_string] => [db_error: message="DB Error: unknown error" code=-1 mode=callback callback=CRM_Core_Error::exceptionHandler prefix="" info="
    DELETE gc
    FROM civicrm_group_contact_cache gc
    INNER JOIN civicrm_group g ON g.id = gc.group_id
    WHERE g.cache_date <= '20190107023003'
   [nativecode=1213 ** Deadlock found when trying to get lock; try restarting transaction]"]

)

...

Jan 07 02:30:03 [info] Retrying after Database deadlock encountered hit on attempt 1 at query : DELETE gc FROM civicrm_group_contact_cache gc INNER JOIN civicrm_group g ON g.id = gc.group_id WHERE g.cache_date <= '20190107023003'

Jan 07 02:30:03 [info] $Fatal Error Details = Array ( [callback] => Array ( [0] => CRM_Core_Error [1] => exceptionHandler )

[code] => -1
[message] => DB Error: unknown error
[mode] => 16
[debug_info] => INSERT IGNORE INTO civicrm_group_contact_cache (contact_id, group_id)
    SELECT DISTINCT id, group_id FROM civicrm_temp_group_contact_cache192
   [nativecode=1213 ** Deadlock found when trying to get lock; try restarting transaction]
[type] => DB_Error
[user_info] => INSERT IGNORE INTO civicrm_group_contact_cache (contact_id, group_id)
    SELECT DISTINCT id, group_id FROM civicrm_temp_group_contact_cache192
   [nativecode=1213 ** Deadlock found when trying to get lock; try restarting transaction]
[to_string] => [db_error: message="DB Error: unknown error" code=-1 mode=callback callback=CRM_Core_Error::exceptionHandler prefix="" info="INSERT IGNORE INTO civicrm_group_contact_cache (contact_id, group_id)
    SELECT DISTINCT id, group_id FROM civicrm_temp_group_contact_cache192
   [nativecode=1213 ** Deadlock found when trying to get lock; try restarting transaction]"]

)

...

Jan 07 02:30:03 [info] Retrying after Database deadlock encountered hit on attempt 1 at query : INSERT IGNORE INTO civicrm_group_contact_cache (contact_id, group_id) SELECT DISTINCT id, group_id FROM civicrm_temp_group_contact_cache192

Jan 07 02:30:04 [info] Contribution record updated successfully

Jan 07 02:30:04 [info] Success: Database updated

...

Jan 07 02:30:54 [info] $Fatal Error Details = Array ( [callback] => Array ( [0] => CRM_Core_Error [1] => exceptionHandler )

[code] => -1
[message] => DB Error: unknown error
[mode] => 16
[debug_info] => INSERT IGNORE INTO civicrm_group_contact_cache (contact_id, group_id)
    SELECT DISTINCT id, group_id FROM civicrm_temp_group_contact_cache192
   [nativecode=1205 ** Lock wait timeout exceeded; try restarting transaction]
[type] => DB_Error
[user_info] => INSERT IGNORE INTO civicrm_group_contact_cache (contact_id, group_id)
    SELECT DISTINCT id, group_id FROM civicrm_temp_group_contact_cache192
   [nativecode=1205 ** Lock wait timeout exceeded; try restarting transaction]
[to_string] => [db_error: message="DB Error: unknown error" code=-1 mode=callback callback=CRM_Core_Error::exceptionHandler prefix="" info="INSERT IGNORE INTO civicrm_group_contact_cache (contact_id, group_id)
    SELECT DISTINCT id, group_id FROM civicrm_temp_group_contact_cache192
   [nativecode=1205 ** Lock wait timeout exceeded; try restarting transaction]"]

)

...

Jan 07 02:30:54 [info] Retrying after Database lock encountered hit on attempt 2 at query : INSERT IGNORE INTO civicrm_group_contact_cache (contact_id, group_id) SELECT DISTINCT id, group_id FROM civicrm_temp_group_contact_cache192

Jan 07 02:30:54 [info] Contribution record updated successfully

Jan 07 02:30:54 [info] Success: Database updated

adixon commented 5 years ago

Yes, we've started work on a restructure of the code so that the next-scheduled-contribution-date is pushed forward before the payment is taken, and then pulled back in case of confirmed failure. You'll still want to monitor your install for issues like the above, but it'll err more on the side of caution.

For your case - sounds like you've got too many large smart groups? You might change the calculation of smart groups from "on demand" to something else, I suspect you've got a smart group that depends on contributions and that smart group is getting triggered for recalculation during the recurring payment job.

cmmadmin commented 5 years ago

Thanks @adixon I changed 'Run frequency' for the 'Rebuild Smart Group Cache' scheduled job from 'Every time cron job is run' to 'Daily'. Is this what you're referring to? Our scheduled jobs cron runs every 15 minutes, so it's likely that job ran at the same time as the 'iATS Payments Recurring Contributions' job.

2019-01-21
cmmadmin commented 5 years ago

@adixon It's good to hear you are working on a fix. I suspect the seriousness of this situation warrants an additional handshake to fail-safe the process. Would something such as the following be feasible?

  1. Civi pushes next-scheduled-contribution-date forward.
  2. Civi sends payment request to iATS.
  3. iATS processes payment.
  4. iATS sends payment status to Civi (Success, Fail, etc).
  5. Civi receives payment status. If Fail, next-scheduled-contribution-date is reverted.
  6. If Civi does not receive payment status (after a fixed timeout period) then it requests the payment status again from iATS. Repeat this step until a payment status is received.

I suspect that step 6 is what is not being done, which leads to issues when there is a failure or lost message. If the next-scheduled-contribution-date push is simply moved ahead in the process without something like step 6, then we may end up with skipped recurring contributions, correct?

Also, whenever an error occurs could an email be sent to our financial admin to notify them that something failed?

Perhaps there is a more elegant solution. Just brainstorming how we can make this process more reliable which is important to us.

KarinG commented 5 years ago

Thank you for bringing this to our attention. We are prioritizing addressing the workflow to prevent this from happening in future.

adixon commented 5 years ago

Yes, you have nicely described the new flow plan. The previous flow only pushed the next scheduled date forward after getting an answer from iATS, so if iATS processed the payment but that information didn't get back to Civi for whatever reason, then the next job run would re-charge the same card again.

Fortunately, Civi is already checking iATS for completed ACH/EFT payments, so extending this to check for completed cc payments when CiviCRM has been left hanging should be relatively straightforward.

An email with errors sounds like a worthwhile feature as well.

cmmadmin commented 5 years ago

We have been in contact with iATS about this issue. They have indicated it has been escalated to their Senior Support Team. Has any progress been made on the CiviCRM side? Perhaps you could coordinate with them to implement the fix?

I have provided iATS with an excerpt of the CiviCRM log files during the time the issue occurred and directed them to the issue description on this page.

KarinG commented 5 years ago

We have added edits in the code base to change the handling of next scheduled date workflow - and are in the process of running our test matrix prior to releasing it.

martinh-pw commented 5 years ago

Hi there, is this change in master now? I'm guessing that's from March 25? - https://github.com/iATSPayments/com.iatspayments.civicrm/commit/cf4de1ebcfdd38cf6dfba7825f0e3350ff3c42db

We're having a similar issue, but might not be quite the same. Will try updating to the latest code as part of fixing it.

We're getting duplicates of all recurring contributions, which shows up in the journal in iATS, but no record of this in Civi. Not seeing anything about the 2nd payment at all in the contribution info, Civi "iats payments admin" page, Civi log, or scheduled jobs log.

In the iATS journal, the correct payment shows up at a given time (when the Civi cron job ran), and the duplicate payment shows up about 45 mins later.

This used to be working, then we migrated the site to a different server and ran the drupal/civi software updates. The other issue we've had since then has been problems with outgoing email. So the most likely scenario might be that the payment is trying to send an outgoing email which maybe fails and then the payment is attempted a second time. I'm not sure if that makes sense?

adixon commented 5 years ago

Hi Martin:

I'll guess that your duplicates are recurring contributions still being generated by your old server/site?

The mail issue is usually just one of optics for the donor (i.e. they think their donation hasn't gone through but it has), but the Civi-Iats admin page and the iATS server have no disagreement about what's going on.

martinh-pw commented 5 years ago

The old site, of course... sigh >_< Thanks for the help :)

kelizoliva commented 5 years ago

We are experiencing the same issue as the OP for one of our clients. Glad to see that this issue is known and being addressed. Is there any sense of an ETA yet of the related PRs being tagged for release?

cmmadmin commented 3 years ago

@adixon @KarinG This appears to be happening again at an increasing rate.

On April 21, April 23 and May 2 several ACH donations and credit card donations were duplicated in iATS. These recurring donations were scheduled to run on April 21, April 23 and May 2 respectively. They did run in iATS, but did not run in Civi and are not listed in the scheduled jobs log. Since the donations did not show as completed in Civi they ran again the following night in both iATS and Civi. Our team had to manually input the donations from the first night into Civi and reach out to each donor with the issue.

We upgraded the iATS extension to 1.7.4 a couple of months ago.

The 'Rebuild Smart Group Cache' scheduled job was set to run Weekly and last ran on April 29. I went agahed disabled it today just to be safe. Doesn't seem like this should apply though(?)

Is there any way we can prevent this? Please let me know if I can provide more information.

I found this error in the CiviCRM Log (not sure if it is related to this issue):

May 02 02:37:08 [error] $Fatal Error Details = Array
(
[callback] => Array
(
[0] => CRM_Core_Error
[1] => exceptionHandler
)

[code] => -3
[message] => DB Error: constraint violation
[mode] => 16
[debug_info] => INSERT INTO `civicrm_entity_financial_trxn` (`entity_table` , `entity_id` , `financial_trxn_id` , `amount` ) VALUES ('civicrm_financial_item' , 210516 , 313768 , 50.00 ) [nativecode=1452 ** Cannot add or update a child row: a foreign key constraint fails (`secure_civi`.`civicrm_entity_financial_trxn`, CONSTRAINT `FK_civicrm_entity_financial_trxn_financial_trxn_id` FOREIGN KEY (`financial_trxn_id`) REFERENCES `civicrm_financial_trxn` (`id`) ON D)]
[type] => DB_Error
[user_info] => INSERT INTO `civicrm_entity_financial_trxn` (`entity_table` , `entity_id` , `financial_trxn_id` , `amount` ) VALUES ('civicrm_financial_item' , 210516 , 313768 , 50.00 ) [nativecode=1452 ** Cannot add or update a child row: a foreign key constraint fails (`secure_civi`.`civicrm_entity_financial_trxn`, CONSTRAINT `FK_civicrm_entity_financial_trxn_financial_trxn_id` FOREIGN KEY (`financial_trxn_id`) REFERENCES `civicrm_financial_trxn` (`id`) ON D)]
[to_string] => [db_error: message="DB Error: constraint violation" code=-3 mode=callback callback=CRM_Core_Error::exceptionHandler prefix="" info="INSERT INTO `civicrm_entity_financial_trxn` (`entity_table` , `entity_id` , `financial_trxn_id` , `amount` ) VALUES ('civicrm_financial_item' , 210516 , 313768 , 50.00 ) [nativecode=1452 ** Cannot add or update a child row: a foreign key constraint fails (`secure_civi`.`civicrm_entity_financial_trxn`, CONSTRAINT `FK_civicrm_entity_financial_trxn_financial_trxn_id` FOREIGN KEY (`financial_trxn_id`) REFERENCES `civicrm_financial_trxn` (`id`) ON D)]"]
)
adixon commented 3 years ago

Fascinating, but first off I'd recommend you start a new issue.

In this case, that constraint violation error sounds like it could be the root of the problem. Specifically, the recurring payment job will try and create a (pending) contribution, then it'll try and take the money, and then it'll complete the contribution. If there are internal civicrm errors in the creation or completion of the contribution, there's going to be trouble. If you can get a backtrace and see at what point this error is happening, we'd probably get a better clue. It looks like it's happening at the contribution completion stage, and the foreign key constraint failure suggests that the real issue came immediately before this one.

cmmadmin commented 3 years ago

Thanks for the response. Here's more context from the Civi log. Does this help?

May 02 02:16:06  [debug] $backTrace = #0 /var/www/webadmin/data/www/acme.org/sites/all/modules/civicrm/CRM/Core/Error.php(419): CRM_Core_Error::backtrace("backTrace", TRUE)
#1 /var/www/webadmin/data/www/acme.org/sites/all/modules/civicrm/CRM/Core/Invoke.php(39): CRM_Core_Error::handleUnhandledException(Object(CRM_Contribute_Exception_InactiveContributionPageException))
#2 /var/www/webadmin/data/www/acme.org/sites/all/modules/civicrm/drupal/civicrm.module(456): CRM_Core_Invoke::invoke((Array:3))
#3 /var/www/webadmin/data/www/acme.org/includes/menu.inc(527): civicrm_invoke("contribute", "transact")
#4 /var/www/webadmin/data/www/acme.org/index.php(21): menu_execute_active_handler()
#5 {main}

May 02 02:37:02  [info] Contribution record updated successfully

May 02 02:37:02  [info] Success: Database updated

May 02 02:37:02  [info] Contribution record updated successfully

May 02 02:37:02  [info] Success: Database updated

May 02 02:37:04  [info] Contribution record updated successfully

May 02 02:37:04  [info] Success: Database updated

May 02 02:37:08  [error] $Fatal Error Details = Array
(
    [callback] => Array
        (
            [0] => CRM_Core_Error
            [1] => exceptionHandler
        )

    [code] => -3
    [message] => DB Error: constraint violation
    [mode] => 16
    [debug_info] => INSERT INTO `civicrm_entity_financial_trxn` (`entity_table` , `entity_id` , `financial_trxn_id` , `amount` ) VALUES ('civicrm_financial_item' ,  210516 ,  313768 ,  50.00 )  [nativecode=1452 ** Cannot add or update a child row: a foreign key constraint fails (`secure_civi`.`civicrm_entity_financial_trxn`, CONSTRAINT `FK_civicrm_entity_financial_trxn_financial_trxn_id` FOREIGN KEY (`financial_trxn_id`) REFERENCES `civicrm_financial_trxn` (`id`) ON D)]
    [type] => DB_Error
    [user_info] => INSERT INTO `civicrm_entity_financial_trxn` (`entity_table` , `entity_id` , `financial_trxn_id` , `amount` ) VALUES ('civicrm_financial_item' ,  210516 ,  313768 ,  50.00 )  [nativecode=1452 ** Cannot add or update a child row: a foreign key constraint fails (`secure_civi`.`civicrm_entity_financial_trxn`, CONSTRAINT `FK_civicrm_entity_financial_trxn_financial_trxn_id` FOREIGN KEY (`financial_trxn_id`) REFERENCES `civicrm_financial_trxn` (`id`) ON D)]
    [to_string] => [db_error: message="DB Error: constraint violation" code=-3 mode=callback callback=CRM_Core_Error::exceptionHandler prefix="" info="INSERT INTO `civicrm_entity_financial_trxn` (`entity_table` , `entity_id` , `financial_trxn_id` , `amount` ) VALUES ('civicrm_financial_item' ,  210516 ,  313768 ,  50.00 )  [nativecode=1452 ** Cannot add or update a child row: a foreign key constraint fails (`secure_civi`.`civicrm_entity_financial_trxn`, CONSTRAINT `FK_civicrm_entity_financial_trxn_financial_trxn_id` FOREIGN KEY (`financial_trxn_id`) REFERENCES `civicrm_financial_trxn` (`id`) ON D)]"]
)

May 02 02:37:08  [debug] $backTrace = #0 /var/www/webadmin/data/www/acme.org/sites/all/modules/civicrm/CRM/Core/Error.php(915): CRM_Core_Error::backtrace("backTrace", TRUE)
#1 /var/www/webadmin/data/www/acme.org/sites/all/modules/civicrm/vendor/pear/pear-core-minimal/src/PEAR.php(922): CRM_Core_Error::exceptionHandler(Object(DB_Error))
#2 /var/www/webadmin/data/www/acme.org/sites/all/modules/civicrm/packages/DB.php(997): PEAR_Error->__construct("DB Error: constraint violation", -3, 16, (Array:2), "INSERT INTO `civicrm_entity_financial_trxn` (`entity_table` , `entity_id` , `...")
#3 /var/www/webadmin/data/www/acme.org/sites/all/modules/civicrm/vendor/pear/pear-core-minimal/src/PEAR.php(575): DB_Error->__construct(-3, 16, (Array:2), "INSERT INTO `civicrm_entity_financial_trxn` (`entity_table` , `entity_id` , `...")
#4 /var/www/webadmin/data/www/acme.org/sites/all/modules/civicrm/vendor/pear/pear-core-minimal/src/PEAR.php(223): PEAR->_raiseError(Object(DB_mysqli), NULL, -3, 16, (Array:2), "INSERT INTO `civicrm_entity_financial_trxn` (`entity_table` , `entity_id` , `...", "DB_Error", TRUE)
#5 /var/www/webadmin/data/www/acme.org/sites/all/modules/civicrm/packages/DB/common.php(1925): PEAR->__call("raiseError", (Array:7))
#6 /var/www/webadmin/data/www/acme.org/sites/all/modules/civicrm/packages/DB/mysqli.php(935): DB_common->raiseError(-3, NULL, NULL, "INSERT INTO `civicrm_entity_financial_trxn` (`entity_table` , `entity_id` , `...", "1452 ** Cannot add or update a child row: a foreign key constraint fails (`se...")
#7 /var/www/webadmin/data/www/acme.org/sites/all/modules/civicrm/packages/DB/mysqli.php(405): DB_mysqli->mysqliRaiseError()
#8 /var/www/webadmin/data/www/acme.org/sites/all/modules/civicrm/packages/DB/common.php(1231): DB_mysqli->simpleQuery("INSERT INTO `civicrm_entity_financial_trxn` (`entity_table` , `entity_id` , `...")
#9 /var/www/webadmin/data/www/acme.org/sites/all/modules/civicrm/packages/DB/DataObject.php(2696): DB_common->query("INSERT INTO `civicrm_entity_financial_trxn` (`entity_table` , `entity_id` , `...")
#10 /var/www/webadmin/data/www/acme.org/sites/all/modules/civicrm/packages/DB/DataObject.php(1245): DB_DataObject->_query("INSERT INTO `civicrm_entity_financial_trxn` (`entity_table` , `entity_id` , `...")
#11 /var/www/webadmin/data/www/acme.org/sites/all/modules/civicrm/CRM/Core/DAO.php(555): DB_DataObject->insert()
#12 /var/www/webadmin/data/www/acme.org/sites/all/modules/civicrm/CRM/Financial/BAO/FinancialItem.php(183): CRM_Core_DAO->save()
#13 /var/www/webadmin/data/www/acme.org/sites/all/modules/civicrm/CRM/Financial/BAO/FinancialItem.php(160): CRM_Financial_BAO_FinancialItem::createEntityTrxn((Array:4))
#14 /var/www/webadmin/data/www/acme.org/sites/all/modules/civicrm/CRM/Financial/BAO/FinancialItem.php(113): CRM_Financial_BAO_FinancialItem::create((Array:9), NULL, (Array:1))
#15 /var/www/webadmin/data/www/acme.org/sites/all/modules/civicrm/CRM/Price/BAO/LineItem.php(450): CRM_Financial_BAO_FinancialItem::add(Object(CRM_Price_BAO_LineItem), Object(CRM_Contribute_BAO_Contribution))
#16 /var/www/webadmin/data/www/acme.org/sites/all/modules/civicrm/CRM/Contribute/BAO/Contribution.php(3838): CRM_Price_BAO_LineItem::processPriceSet(401618, (Array:1), Object(CRM_Contribute_BAO_Contribution), "civicrm_contribution", FALSE)
#17 /var/www/webadmin/data/www/acme.org/sites/all/modules/civicrm/CRM/Contribute/BAO/Contribution.php(231): CRM_Contribute_BAO_Contribution::recordFinancialAccounts((Array:24))
#18 /var/www/webadmin/data/www/acme.org/sites/all/modules/civicrm/CRM/Contribute/BAO/Contribution.php(512): CRM_Contribute_BAO_Contribution::add((Array:24))
#19 /var/www/webadmin/data/www/acme.org/sites/all/modules/civicrm/api/v3/utils.php(1294): CRM_Contribute_BAO_Contribution::create((Array:24), (Array:1))
#20 /var/www/webadmin/data/www/acme.org/sites/all/modules/civicrm/api/v3/Contribution.php(77): _civicrm_api3_basic_create("CRM_Contribute_BAO_Contribution", (Array:24), "Contribution")
#21 /var/www/webadmin/data/www/acme.org/sites/all/modules/civicrm/Civi/API/Provider/MagicFunctionProvider.php(89): civicrm_api3_contribution_create((Array:24))
#22 /var/www/webadmin/data/www/acme.org/sites/all/modules/civicrm/Civi/API/Kernel.php(150): Civi\API\Provider\MagicFunctionProvider->invoke((Array:8))
#23 /var/www/webadmin/data/www/acme.org/sites/all/modules/civicrm/Civi/API/Kernel.php(81): Civi\API\Kernel->runRequest((Array:8))
#24 /var/www/webadmin/data/www/acme.org/sites/all/modules/civicrm/api/api.php(131): Civi\API\Kernel->runSafe("Contribution", "create", (Array:17))
#25 /var/www/webadmin/data/www/acme.org/sites/all/modules/civicrm/CRM/Contribute/BAO/Contribution.php(2668): civicrm_api3("Contribution", "create", (Array:17))
#26 /var/www/webadmin/data/www/acme.org/sites/all/modules/civicrm/CRM/Contribute/BAO/Contribution.php(4511): CRM_Contribute_BAO_Contribution::repeatTransaction(Object(CRM_Contribute_BAO_Contribution), (Array:12), (Array:16), "13")
#27 /var/www/webadmin/data/www/acme.org/sites/all/modules/civicrm/api/v3/Contribution.php(679): CRM_Contribute_BAO_Contribution::completeOrder((Array:12), (Array:9), (Array:7), Object(CRM_Core_Transaction), Object(CRM_Contribute_BAO_Contribution), NULL)
#28 /var/www/webadmin/data/www/acme.org/sites/all/modules/civicrm/api/v3/Contribution.php(621): _ipn_process_transaction((Array:6), Object(CRM_Contribute_BAO_Contribution), (Array:10), (Array:9), Object(CRM_Contribute_BAO_Contribution))
#29 /var/www/webadmin/data/www/acme.org/sites/all/modules/civicrm/Civi/API/Provider/MagicFunctionProvider.php(89): civicrm_api3_contribution_repeattransaction((Array:6))
#30 /var/www/webadmin/data/www/acme.org/sites/all/modules/civicrm/Civi/API/Kernel.php(150): Civi\API\Provider\MagicFunctionProvider->invoke((Array:8))
#31 /var/www/webadmin/data/www/acme.org/sites/all/modules/civicrm/Civi/API/Kernel.php(81): Civi\API\Kernel->runRequest((Array:8))
#32 /var/www/webadmin/data/www/acme.org/sites/all/modules/civicrm/api/api.php(131): Civi\API\Kernel->runSafe("Contribution", "repeattransaction", (Array:5))
#33 /var/www/webadmin/data/www/acme.org/sites/default/files/civicrm_extensions/com.iatspayments.civicrm/CRM/Iats/Transaction.php(128): civicrm_api3("Contribution", "repeattransaction", (Array:5))
#34 /var/www/webadmin/data/www/acme.org/sites/default/files/civicrm_extensions/com.iatspayments.civicrm/api/v3/Job/Iatsrecurringcontributions.php(243): CRM_Iats_Transaction::process_contribution_payment((Array:20), (Array:19), (Array:6))
#35 /var/www/webadmin/data/www/acme.org/sites/all/modules/civicrm/Civi/API/Provider/MagicFunctionProvider.php(89): civicrm_api3_job_Iatsrecurringcontributions((Array:1))
#36 /var/www/webadmin/data/www/acme.org/sites/all/modules/civicrm/Civi/API/Kernel.php(150): Civi\API\Provider\MagicFunctionProvider->invoke((Array:8))
#37 /var/www/webadmin/data/www/acme.org/sites/all/modules/civicrm/Civi/API/Kernel.php(81): Civi\API\Kernel->runRequest((Array:8))
#38 /var/www/webadmin/data/www/acme.org/sites/all/modules/civicrm/api/api.php(22): Civi\API\Kernel->runSafe("Job", "iatsrecurringcontributions", (Array:1))
#39 /var/www/webadmin/data/www/acme.org/sites/all/modules/civicrm/CRM/Core/JobManager.php(133): civicrm_api("Job", "iatsrecurringcontributions", (Array:1))
#40 /var/www/webadmin/data/www/acme.org/sites/all/modules/civicrm/CRM/Core/JobManager.php(92): CRM_Core_JobManager->executeJob(Object(CRM_Core_ScheduledJob))
#41 /var/www/webadmin/data/www/acme.org/sites/all/modules/civicrm/bin/cron.php(37): CRM_Core_JobManager->executeJobByAction("job", "iatsrecurringcontributions")
#42 {main}

May 02 02:37:09  [info] Contribution record updated successfully

May 02 02:37:09  [info] Success: Database updated

May 02 02:37:09  [info] Contribution record updated successfully

May 02 02:37:09  [info] Success: Database updated

May 02 02:37:09  [info] Contribution record updated successfully

May 02 02:37:10  [info] Success: Database updated

May 02 02:37:10  [info] Contribution record updated successfully

May 02 02:37:10  [info] Success: Database updated

May 02 02:37:11  [info] Contribution record updated successfully

May 02 02:37:12  [info] Success: Database updated

May 02 02:37:12  [info] Contribution record updated successfully

May 02 02:37:12  [info] Success: Database updated

May 02 02:37:12  [info] Contribution record updated successfully

May 02 02:37:12  [info] Success: Database updated

May 02 02:37:12  [info] Contribution record updated successfully

May 02 02:37:12  [info] Success: Database updated

May 02 02:37:13  [info] Contribution record updated successfully

May 02 02:37:13  [info] Success: Database updated

May 02 02:37:13  [info] Contribution record updated successfully

May 02 02:37:13  [info] Success: Database updated

May 02 02:37:13  [info] Contribution record updated successfully

May 02 02:37:13  [info] Success: Database updated

May 02 02:37:14  [info] Contribution record updated successfully

May 02 02:37:14  [info] Success: Database updated

May 02 02:37:15  [info] Contribution record updated successfully

May 02 02:37:15  [info] Success: Database updated

May 02 02:37:15  [info] Contribution record updated successfully

May 02 02:37:15  [info] Success: Database updated

May 02 02:37:15  [info] Contribution record updated successfully

May 02 02:37:15  [info] Success: Database updated

May 02 02:37:16  [info] Contribution record updated successfully

May 02 02:37:16  [info] Success: Database updated

May 02 02:37:17  [info] Contribution record updated successfully

May 02 02:37:17  [info] Success: Database updated

May 02 02:37:18  [info] Contribution record updated successfully

May 02 02:37:18  [info] Success: Database updated

May 02 02:37:18  [info] Contribution record updated successfully

May 02 02:37:18  [info] Success: Database updated

May 02 02:37:18  [info] $Unexpected Exception = CiviCRM_API3_Exception Object
(
    [extraParams:CiviCRM_API3_Exception:private] => Array
        (
            [is_error] => 1
            [error_message] => Expected one Contribution but found 0
            [error_code] => undefined
        )

    [message:protected] => Expected one Contribution but found 0
    [string:Exception:private] => 
    [code:protected] => 0
    [file:protected] => /var/www/webadmin/data/www/acme.org/sites/all/modules/civicrm/api/api.php
    [line:protected] => 133
    [trace:Exception:private] => Array
(
            [0] => Array
                (
                    [file] => /var/www/webadmin/data/www/acme.org/sites/default/files/civicrm_extensions/com.iatspayments.civicrm/CRM/Iats/Transaction.php
                    [line] => 174
                    [function] => civicrm_api3
                    [args] => Array
                        (
                            [0] => Contribution
                            [1] => create
                            [2] => Array
                                (
                                    [id] => 401635
                                    [trxn_id] => AD5EFF7A:1619941038
                                    [version] => 3
                                )

                        )

                )

            [1] => Array
                (
                    [file] => /var/www/webadmin/data/www/acme.org/sites/default/files/civicrm_extensions/com.iatspayments.civicrm/api/v3/Job/Iatsrecurringcontributions.php
                    [line] => 243
                    [function] => process_contribution_payment
                    [class] => CRM_Iats_Transaction
                    [type] => ::
                    [args] => Array
                        (
                            [0] => Array
                                (
                                    [version] => 3
                                    [contact_id] => 171955
                                    [receive_date] => 20210502023718
                                    [total_amount] => 20.00
                                    [payment_instrument_id] => 2
                                    [contribution_recur_id] => 8368
                                    [invoice_id] => 7d4ccbf3b871384de124d3b77c28eb7c
                                    [source] => iATS Payments (iATSServiceACHEFT) Recurring Contribution ( id = 8368 )
                                    [contribution_status_id] => 2
                                    [currency] => USD
                                    [payment_processor] => 15
                                    [is_test] => 0
                                    [financial_type_id] => 498
                                    [is_email_receipt] => 0
                                    [contribution_campaign_id] => 11
                                    [amount_level] => 
                                    [original_contribution_id] => 397669
                                    [skipLineItem] => 1
                                    [api.line_item.create] => Array
                                        (
                                            [0] => Array
                                                (
                                                    [price_field_id] => 458
                                                    [qty] => 1.00
                                                    [line_total] => 20.00
                                                    [unit_price] => 20.00
                                                    [label] => Other Amount
                                                    [price_field_value_id] => 697
                                                    [financial_type_id] => 498
                                                )

                                        )

                                    [trxn_id] => AD5EFF7A:1619941038
                                    [id] => 401635
                                )

                            [1] => Array
                                (
                                    [id] => 15
                                    [domain_id] => 1
                                    [name] => Virtual Check (EFT)
                                    [description] => ACH-EFT (iATS)
                                    [payment_processor_type_id] => 20
                                    [is_active] => 1
                                    [is_default] => 0
                                    [is_test] => 0
                                    [user_name] => xxxxxxxxxxx
                                    [password] => xxxxxxxxxxxx
                                    [url_site] => https://www.iatspayments.com/NetGate/ProcessLinkv2.asmx?WSDL
                                    [url_recur] => https://www.iatspayments.com/NetGate/ProcessLinkv2.asmx?WSDL
                                    [class_name] => Payment_iATSServiceACHEFT
                                    [billing_mode] => 1
                                    [is_recur] => 1
                                    [payment_type] => 2
                                    [payment_instrument_id] => 2
                                )

                            [2] => Array
                                (
                                    [id] => 2983
                                    [contact_id] => 171955
                                    [payment_processor_id] => 15
                                    [token] => A23022741
                                    [created_date] => 2020-03-23 13:47:59
                                    [email] => xxxxxxxxxx@gmail.com
                                    [ip_address] => 12.151.215.66
                                )

                        )

                )

            [2] => Array
                (
                    [file] => /var/www/webadmin/data/www/acme.org/sites/all/modules/civicrm/Civi/API/Provider/MagicFunctionProvider.php
                    [line] => 89
                    [function] => civicrm_api3_job_Iatsrecurringcontributions
                    [args] => Array
                        (
                            [0] => Array
                                (
                                    [version] => 3
                                )

                        )

                )

            [3] => Array
                (
                    [file] => /var/www/webadmin/data/www/acme.org/sites/all/modules/civicrm/Civi/API/Kernel.php
                    [line] => 150
                    [function] => invoke
                    [class] => Civi\API\Provider\MagicFunctionProvider
                    [type] => ->
                    [args] => Array
                        (
                            [0] => Array
                                (
                                    [id] => 1
                                    [version] => 3
                                    [params] => Array
                                        (
                                            [version] => 3
                                        )

                                    [fields] => Array
                                        (
                                            [recur_id] => Array
                                                (
                                                    [name] => recur_id
                                                    [title] => Recurring payment id
                                                    [api.required] => 0
                                                    [type] => 1
                                                )

                                            [cycle_day] => Array
                                                (
                                                    [name] => cycle_day
                                                    [title] => Only contributions that match a specific cycle day.
                                                    [api.required] => 0
                                                    [type] => 1
                                                )

                                            [failure_count] => Array
                                                (
                                                    [name] => failure_count
                                                    [title] => Filter by number of failure counts
                                                    [api.required] => 0
                                                    [type] => 1
                                                )

                                            [catchup] => Array
                                                (
                                                    [title] => Process as if in the past to catch up.
                                                    [api.required] => 0
                                                    [name] => catchup
                                                )

                                            [ignoremembership] => Array
                                                (
                                                    [title] => Ignore memberships
                                                    [api.required] => 0
                                                    [name] => ignoremembership
                                                )

                                        )

                                    [entity] => Job
                                    [action] => iatsrecurringcontributions
                                    [function] => civicrm_api3_job_iatsrecurringcontributions
                                    [is_generic] => 
                                )

                        )

                )

            [4] => Array
                (
                    [file] => /var/www/webadmin/data/www/acme.org/sites/all/modules/civicrm/Civi/API/Kernel.php
                    [line] => 81
                    [function] => runRequest
                    [class] => Civi\API\Kernel
                    [type] => ->
                    [args] => Array
                        (
                            [0] => Array
                                (
                                    [id] => 1
                                    [version] => 3
                                    [params] => Array
                                        (
                                            [version] => 3
                                        )

                                    [fields] => Array
                                        (
                                            [recur_id] => Array
                                                (
                                                    [name] => recur_id
                                                    [title] => Recurring payment id
                                                    [api.required] => 0
                                                    [type] => 1
                                                )

                                            [cycle_day] => Array
                                                (
                                                    [name] => cycle_day
                                                    [title] => Only contributions that match a specific cycle day.
                                                    [api.required] => 0
                                                    [type] => 1
                                                )

                                            [failure_count] => Array
                                                (
                                                    [name] => failure_count
                                                    [title] => Filter by number of failure counts
                                                    [api.required] => 0
                                                    [type] => 1
                                                )

                                            [catchup] => Array
                                                (
                                                    [title] => Process as if in the past to catch up.
                                                    [api.required] => 0
                                                    [name] => catchup
                                                )

                                            [ignoremembership] => Array
                                                (
                                                    [title] => Ignore memberships
                                                    [api.required] => 0
                                                    [name] => ignoremembership
                                                )

                                        )

                                    [entity] => Job
                                    [action] => iatsrecurringcontributions
                                    [function] => civicrm_api3_job_iatsrecurringcontributions
                                    [is_generic] => 
                                )

                        )

                )

            [5] => Array
                (
                    [file] => /var/www/webadmin/data/www/acme.org/sites/all/modules/civicrm/api/api.php
                    [line] => 22
                    [function] => runSafe
                    [class] => Civi\API\Kernel
                    [type] => ->
                    [args] => Array
                        (
                            [0] => Job
                            [1] => iatsrecurringcontributions
                            [2] => Array
                                (
                                    [version] => 3
                                )

                        )

                )

            [6] => Array
                (
                    [file] => /var/www/webadmin/data/www/acme.org/sites/all/modules/civicrm/CRM/Core/JobManager.php
                    [line] => 133
                    [function] => civicrm_api
                    [args] => Array
                        (
                            [0] => Job
                            [1] => iatsrecurringcontributions
                            [2] => Array
                                (
                                    [version] => 3
                                )

                        )

                )

            [7] => Array
                (
                    [file] => /var/www/webadmin/data/www/acme.org/sites/all/modules/civicrm/CRM/Core/JobManager.php
                    [line] => 92
                    [function] => executeJob
                    [class] => CRM_Core_JobManager
                    [type] => ->
                    [args] => Array
                        (
                            [0] => CRM_Core_ScheduledJob Object
                                (
                                    [version] => 3
                                    [name] => iATS Payments Recurring Contributions
                                    [apiParams] => Array
                                        (
                                            [version] => 3
                                        )

                                    [remarks] => Array
                                        (
                                        )

                                    [id] => 24
                                    [domain_id] => 1
                                    [run_frequency] => Daily
                                    [last_run] => 2021-05-01 02:37:01
                                    [description] => Trigger + Generate recurring contributions for iATS Payments
                                    [api_entity] => Job
                                    [api_action] => iatsrecurringcontributions
                                    [is_active] => 0
                                )

                        )

                )

            [8] => Array
                (
                    [file] => /var/www/webadmin/data/www/acme.org/sites/all/modules/civicrm/bin/cron.php
                    [line] => 37
                    [function] => executeJobByAction
                    [class] => CRM_Core_JobManager
                    [type] => ->
                    [args] => Array
                        (
                            [0] => job
                            [1] => iatsrecurringcontributions
                        )

                )

        )

    [previous:Exception:private] => 
)

May 02 02:37:19  [info] Contribution record updated successfully

May 02 02:37:19  [info] Success: Database updated  
adixon commented 3 years ago

Ah yes - so the error happens within the call to the repeattransaction api.

I've seen that there have been some updates to the ipn code in the last few civi versions, I suspect that's where this is coming from.

https://lab.civicrm.org/dev/core/-/issues?scope=all&utf8=%E2%9C%93&state=closed&search=ipn

In terms of how to fix it, I suspect there are some kind of edge-case type things at work here, since it's not failing for all of your contributions. If you can look at the ones that are failing and see any patterns, that might help.

Specifically, I'd look for the associated price sets for the failing recurring contributions and see if there are weirdnesses that might be cleaned up.

cmmadmin commented 3 years ago

@adixon We don't see any differences with the contributions that are failing so far, but we'll keep looking.

Also, I forgot to include our version info: CiviCRM 5.24.5 Drupal 7.69 iATS 1.7.4

cmmadmin commented 3 years ago

@adixon Thank you for looking into this. As you can expect this is an important issue for us to get resolved. We are happy to provide whatever information and assistance we can.

We have many contribution pages as we create one for each staff member that raises support. Each contribution page is setup exactly the same and we haven't found any differences with the ones that failed.

We do not use Price Sets but simply set them up with Financial Types and Financial Accounts as shown in the attached screenshots.

Is there anything we can inspect in the database tables that would be helpful?

Or, are these some log messages that we could add to our CiviCRM code that would be helpful to troubleshoot this issue if it occurs again? If so, if you can provide the code changes I can apply them to our installation.

We do have a large number of financial types and we do use the Summary Fields extension which has a scheduled job which is set to run monthly. I just mention that in case these could be culprits. The execution of the Summary Fields scheduled job do not correspond with the timing of these recurring contribution failures so doesn't seem to make sense that is doing it but perhaps it is leaving behind some residual effects?

Please let us know if there is anything we can do to help get this resolved. Thank you.

Screenshot 2021-05-07 042653 Screenshot 2021-05-07 042855 Screenshot 2021-05-07 042456 Screenshot 2021-05-07 042519

KarinG commented 3 years ago

Reviewing the output -> I do see references to price sets -> price_field_id as well as price_field_value_id -> Could it be that the original series for this contact id [171955] was created with a price set [dating back to before you stopped using them?] and perhaps this field no longer exists?

                                                [price_field_id] => 458
                                                [qty] => 1.00
                                                [line_total] => 20.00
                                                [unit_price] => 20.00
                                                [label] => Other Amount
                                                [price_field_value_id] => 697
                                                [financial_type_id] => 498
adixon commented 3 years ago

@KarinG - I believe that even when you don't "use" price sets explicitly, when you input the allowed amounts for a contribution page, it implements that as a 'hidden' priceset.

cmmadmin commented 3 years ago

@adixon @KarinG

CiviCRM 5.24.5 Drupal 7.69 Recurring Active Donors Custom Search (com.backofficethinking.activedonorssearch) version 1.0 iATS Payments (com.iatspayments.civicrm) version 1.7.4 Summary Fields (net.ourpowerbase.sumfields) version 4.0.2 FlexMailer (org.civicrm.flexmailer) version 1.1.1 CiviDiscount (org.civicrm.module.cividiscount) version 3.8.1 CiviCRM Bootstrap theme (org.civicrm.shoreditch) version 0.1.0-alpha.36 Sequential credit notes (sequentialcreditnotes) version 1.0 Mosaico (uk.co.vedaconsulting.mosaico) version 2.5.1597918155

This issue has occurred again. Several recurring contributions ran two days in a row (May 19 and May 20).

Error in Civi log is: [message] => DB Error: database lock timeout

Excerpt from Civi log is below.

The SumFields extension has a scheduled job that I previously set to run Quarterly. I noticed today this scheduled job had reset itself to run Hourly. Could this be the culprit? We have a long list of financial types that are are configured to used with the SumFields calculations.

May 19 02:37:53  [error] $Fatal Error Details = Array
(
    [callback] => Array
        (
            [0] => CRM_Core_Error
            [1] => exceptionHandler
        )

    [code] => -30
    [message] => DB Error: database lock timeout
    [mode] => 16
    [debug_info] => INSERT INTO `civicrm_contribution` (`contact_id` , `financial_type_id` , `payment_instrument_id` , `receive_date` , `total_amount` , `fee_amount` , `net_amount` , `currency` , `source` , `contribution_recur_id` , `is_test` , `contribution_status_id` , `check_number` , `campaign_id` ) VALUES ( 116272 ,  47 ,  2 ,  20210519023702 ,  100.00 ,  0 ,  100 , 'USD' , 'iATS Payments (iATSServiceACHEFT) Recurring Contribution ( id = 5146 )' ,  5146 ,  0 ,  2 ,  NULL ,  11 )  [nativecode=1205 ** Lock wait timeout exceeded; try restarting transaction]
    [type] => DB_Error
    [user_info] => INSERT INTO `civicrm_contribution` (`contact_id` , `financial_type_id` , `payment_instrument_id` , `receive_date` , `total_amount` , `fee_amount` , `net_amount` , `currency` , `source` , `contribution_recur_id` , `is_test` , `contribution_status_id` , `check_number` , `campaign_id` ) VALUES ( 116272 ,  47 ,  2 ,  20210519023702 ,  100.00 ,  0 ,  100 , 'USD' , 'iATS Payments (iATSServiceACHEFT) Recurring Contribution ( id = 5146 )' ,  5146 ,  0 ,  2 ,  NULL ,  11 )  [nativecode=1205 ** Lock wait timeout exceeded; try restarting transaction]
    [to_string] => [db_error: message="DB Error: database lock timeout" code=-30 mode=callback callback=CRM_Core_Error::exceptionHandler prefix="" info="INSERT INTO `civicrm_contribution` (`contact_id` , `financial_type_id` , `payment_instrument_id` , `receive_date` , `total_amount` , `fee_amount` , `net_amount` , `currency` , `source` , `contribution_recur_id` , `is_test` , `contribution_status_id` , `check_number` , `campaign_id` ) VALUES ( 116272 ,  47 ,  2 ,  20210519023702 ,  100.00 ,  0 ,  100 , 'USD' , 'iATS Payments (iATSServiceACHEFT) Recurring Contribution ( id = 5146 )' ,  5146 ,  0 ,  2 ,  NULL ,  11 )  [nativecode=1205 ** Lock wait timeout exceeded; try restarting transaction]"]
)

May 19 02:37:53  [debug] $backTrace = #0 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/CRM/Core/Error.php(915): CRM_Core_Error::backtrace("backTrace", TRUE)
#1 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/vendor/pear/pear-core-minimal/src/PEAR.php(922): CRM_Core_Error::exceptionHandler(Object(DB_Error))
#2 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/packages/DB.php(997): PEAR_Error->__construct("DB Error: database lock timeout", -30, 16, (Array:2), "INSERT INTO `civicrm_contribution` (`contact_id` , `financial_type_id` , `pay...")
#3 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/vendor/pear/pear-core-minimal/src/PEAR.php(575): DB_Error->__construct(-30, 16, (Array:2), "INSERT INTO `civicrm_contribution` (`contact_id` , `financial_type_id` , `pay...")
#4 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/vendor/pear/pear-core-minimal/src/PEAR.php(223): PEAR->_raiseError(Object(DB_mysqli), NULL, -30, 16, (Array:2), "INSERT INTO `civicrm_contribution` (`contact_id` , `financial_type_id` , `pay...", "DB_Error", TRUE)
#5 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/packages/DB/common.php(1925): PEAR->__call("raiseError", (Array:7))
#6 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/packages/DB/mysqli.php(935): DB_common->raiseError(-30, NULL, NULL, "INSERT INTO `civicrm_contribution` (`contact_id` , `financial_type_id` , `pay...", "1205 ** Lock wait timeout exceeded; try restarting transaction")
#7 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/packages/DB/mysqli.php(405): DB_mysqli->mysqliRaiseError()
#8 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/packages/DB/common.php(1231): DB_mysqli->simpleQuery("INSERT INTO `civicrm_contribution` (`contact_id` , `financial_type_id` , `pay...")
#9 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/packages/DB/DataObject.php(2696): DB_common->query("INSERT INTO `civicrm_contribution` (`contact_id` , `financial_type_id` , `pay...")
#10 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/packages/DB/DataObject.php(1245): DB_DataObject->_query("INSERT INTO `civicrm_contribution` (`contact_id` , `financial_type_id` , `pay...")
#11 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/CRM/Core/DAO.php(555): DB_DataObject->insert()
#12 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/CRM/Contribute/BAO/Contribution.php(215): CRM_Core_DAO->save()
#13 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/CRM/Contribute/BAO/Contribution.php(512): CRM_Contribute_BAO_Contribution::add((Array:23))
#14 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/api/v3/utils.php(1294): CRM_Contribute_BAO_Contribution::create((Array:23), (Array:1))
#15 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/api/v3/Contribution.php(77): _civicrm_api3_basic_create("CRM_Contribute_BAO_Contribution", (Array:23), "Contribution")
#16 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/Civi/API/Provider/MagicFunctionProvider.php(89): civicrm_api3_contribution_create((Array:23))
#17 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/Civi/API/Kernel.php(150): Civi\API\Provider\MagicFunctionProvider->invoke((Array:8))
#18 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/Civi/API/Kernel.php(81): Civi\API\Kernel->runRequest((Array:8))
#19 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/api/api.php(131): Civi\API\Kernel->runSafe("Contribution", "create", (Array:17))
#20 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/CRM/Contribute/BAO/Contribution.php(2668): civicrm_api3("Contribution", "create", (Array:17))
#21 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/CRM/Contribute/BAO/Contribution.php(4511): CRM_Contribute_BAO_Contribution::repeatTransaction(Object(CRM_Contribute_BAO_Contribution), (Array:12), (Array:16), "15")
#22 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/api/v3/Contribution.php(679): CRM_Contribute_BAO_Contribution::completeOrder((Array:12), (Array:9), (Array:7), Object(CRM_Core_Transaction), Object(CRM_Contribute_BAO_Contribution), NULL)
#23 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/api/v3/Contribution.php(621): _ipn_process_transaction((Array:6), Object(CRM_Contribute_BAO_Contribution), (Array:10), (Array:9), Object(CRM_Contribute_BAO_Contribution))
#24 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/Civi/API/Provider/MagicFunctionProvider.php(89): civicrm_api3_contribution_repeattransaction((Array:6))
#25 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/Civi/API/Kernel.php(150): Civi\API\Provider\MagicFunctionProvider->invoke((Array:8))
#26 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/Civi/API/Kernel.php(81): Civi\API\Kernel->runRequest((Array:8))
#27 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/api/api.php(131): Civi\API\Kernel->runSafe("Contribution", "repeattransaction", (Array:5))
#28 /var/www/webadmin/data/www/secure.acme.org/sites/default/files/civicrm_extensions/com.iatspayments.civicrm/CRM/Iats/Transaction.php(128): civicrm_api3("Contribution", "repeattransaction", (Array:5))
#29 /var/www/webadmin/data/www/secure.acme.org/sites/default/files/civicrm_extensions/com.iatspayments.civicrm/api/v3/Job/Iatsrecurringcontributions.php(243): CRM_Iats_Transaction::process_contribution_payment((Array:20), (Array:17), (Array:6))
#30 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/Civi/API/Provider/MagicFunctionProvider.php(89): civicrm_api3_job_Iatsrecurringcontributions((Array:1))
#31 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/Civi/API/Kernel.php(150): Civi\API\Provider\MagicFunctionProvider->invoke((Array:8))
#32 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/Civi/API/Kernel.php(81): Civi\API\Kernel->runRequest((Array:8))
#33 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/api/api.php(22): Civi\API\Kernel->runSafe("Job", "iatsrecurringcontributions", (Array:1))
#34 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/CRM/Core/JobManager.php(133): civicrm_api("Job", "iatsrecurringcontributions", (Array:1))
#35 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/CRM/Core/JobManager.php(92): CRM_Core_JobManager->executeJob(Object(CRM_Core_ScheduledJob))
#36 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/bin/cron.php(37): CRM_Core_JobManager->executeJobByAction("job", "iatsrecurringcontributions")
#37 {main}

May 19 02:37:53  [info] Retrying after Database lock encountered hit on attempt 1 at query : INSERT INTO `civicrm_contribution` (`contact_id` , `financial_type_id` , `payment_instrument_id` , `receive_date` , `total_amount` , `fee_amount` , `net_amount` , `currency` , `source` , `contribution_recur_id` , `is_test` , `contribution_status_id` , `check_number` , `campaign_id` ) VALUES ( 116272 ,  47 ,  2 ,  20210519023702 ,  100.00 ,  0 ,  100 , 'USD' , 'iATS Payments (iATSServiceACHEFT) Recurring Contribution ( id = 5146 )' ,  5146 ,  0 ,  2 ,  NULL ,  11 ) 

May 19 02:38:44  [error] $Fatal Error Details = Array
(
    [callback] => Array
        (
            [0] => CRM_Core_Error
            [1] => exceptionHandler
        )

    [code] => -30
    [message] => DB Error: database lock timeout
    [mode] => 16
    [debug_info] => INSERT INTO `civicrm_contribution` (`contact_id` , `financial_type_id` , `payment_instrument_id` , `receive_date` , `total_amount` , `fee_amount` , `net_amount` , `currency` , `source` , `contribution_recur_id` , `is_test` , `contribution_status_id` , `check_number` , `campaign_id` ) VALUES ( 116272 ,  47 ,  2 ,  20210519023702 ,  100.00 ,  0 ,  100 , 'USD' , 'iATS Payments (iATSServiceACHEFT) Recurring Contribution ( id = 5146 )' ,  5146 ,  0 ,  2 ,  NULL ,  11 )  [nativecode=1205 ** Lock wait timeout exceeded; try restarting transaction]
    [type] => DB_Error
    [user_info] => INSERT INTO `civicrm_contribution` (`contact_id` , `financial_type_id` , `payment_instrument_id` , `receive_date` , `total_amount` , `fee_amount` , `net_amount` , `currency` , `source` , `contribution_recur_id` , `is_test` , `contribution_status_id` , `check_number` , `campaign_id` ) VALUES ( 116272 ,  47 ,  2 ,  20210519023702 ,  100.00 ,  0 ,  100 , 'USD' , 'iATS Payments (iATSServiceACHEFT) Recurring Contribution ( id = 5146 )' ,  5146 ,  0 ,  2 ,  NULL ,  11 )  [nativecode=1205 ** Lock wait timeout exceeded; try restarting transaction]
    [to_string] => [db_error: message="DB Error: database lock timeout" code=-30 mode=callback callback=CRM_Core_Error::exceptionHandler prefix="" info="INSERT INTO `civicrm_contribution` (`contact_id` , `financial_type_id` , `payment_instrument_id` , `receive_date` , `total_amount` , `fee_amount` , `net_amount` , `currency` , `source` , `contribution_recur_id` , `is_test` , `contribution_status_id` , `check_number` , `campaign_id` ) VALUES ( 116272 ,  47 ,  2 ,  20210519023702 ,  100.00 ,  0 ,  100 , 'USD' , 'iATS Payments (iATSServiceACHEFT) Recurring Contribution ( id = 5146 )' ,  5146 ,  0 ,  2 ,  NULL ,  11 )  [nativecode=1205 ** Lock wait timeout exceeded; try restarting transaction]"]
)

May 19 02:38:44  [debug] $backTrace = #0 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/CRM/Core/Error.php(915): CRM_Core_Error::backtrace("backTrace", TRUE)
#1 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/vendor/pear/pear-core-minimal/src/PEAR.php(922): CRM_Core_Error::exceptionHandler(Object(DB_Error))
#2 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/packages/DB.php(997): PEAR_Error->__construct("DB Error: database lock timeout", -30, 16, (Array:2), "INSERT INTO `civicrm_contribution` (`contact_id` , `financial_type_id` , `pay...")
#3 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/vendor/pear/pear-core-minimal/src/PEAR.php(575): DB_Error->__construct(-30, 16, (Array:2), "INSERT INTO `civicrm_contribution` (`contact_id` , `financial_type_id` , `pay...")
#4 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/vendor/pear/pear-core-minimal/src/PEAR.php(223): PEAR->_raiseError(Object(DB_mysqli), NULL, -30, 16, (Array:2), "INSERT INTO `civicrm_contribution` (`contact_id` , `financial_type_id` , `pay...", "DB_Error", TRUE)
#5 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/packages/DB/common.php(1925): PEAR->__call("raiseError", (Array:7))
#6 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/packages/DB/mysqli.php(935): DB_common->raiseError(-30, NULL, NULL, "INSERT INTO `civicrm_contribution` (`contact_id` , `financial_type_id` , `pay...", "1205 ** Lock wait timeout exceeded; try restarting transaction")
#7 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/packages/DB/mysqli.php(405): DB_mysqli->mysqliRaiseError()
#8 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/packages/DB/common.php(1231): DB_mysqli->simpleQuery("INSERT INTO `civicrm_contribution` (`contact_id` , `financial_type_id` , `pay...")
#9 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/packages/DB/DataObject.php(2696): DB_common->query("INSERT INTO `civicrm_contribution` (`contact_id` , `financial_type_id` , `pay...")
#10 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/packages/DB/DataObject.php(1245): DB_DataObject->_query("INSERT INTO `civicrm_contribution` (`contact_id` , `financial_type_id` , `pay...")
#11 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/CRM/Core/DAO.php(555): DB_DataObject->insert()
#12 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/CRM/Contribute/BAO/Contribution.php(215): CRM_Core_DAO->save()
#13 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/CRM/Contribute/BAO/Contribution.php(512): CRM_Contribute_BAO_Contribution::add((Array:23))
#14 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/api/v3/utils.php(1294): CRM_Contribute_BAO_Contribution::create((Array:23), (Array:1))
#15 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/api/v3/Contribution.php(77): _civicrm_api3_basic_create("CRM_Contribute_BAO_Contribution", (Array:23), "Contribution")
#16 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/Civi/API/Provider/MagicFunctionProvider.php(89): civicrm_api3_contribution_create((Array:23))
#17 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/Civi/API/Kernel.php(150): Civi\API\Provider\MagicFunctionProvider->invoke((Array:8))
#18 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/Civi/API/Kernel.php(81): Civi\API\Kernel->runRequest((Array:8))
#19 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/api/api.php(131): Civi\API\Kernel->runSafe("Contribution", "create", (Array:17))
#20 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/CRM/Contribute/BAO/Contribution.php(2668): civicrm_api3("Contribution", "create", (Array:17))
#21 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/CRM/Contribute/BAO/Contribution.php(4511): CRM_Contribute_BAO_Contribution::repeatTransaction(Object(CRM_Contribute_BAO_Contribution), (Array:12), (Array:16), "15")
#22 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/api/v3/Contribution.php(679): CRM_Contribute_BAO_Contribution::completeOrder((Array:12), (Array:9), (Array:7), Object(CRM_Core_Transaction), Object(CRM_Contribute_BAO_Contribution), NULL)
#23 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/api/v3/Contribution.php(621): _ipn_process_transaction((Array:6), Object(CRM_Contribute_BAO_Contribution), (Array:10), (Array:9), Object(CRM_Contribute_BAO_Contribution))
#24 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/Civi/API/Provider/MagicFunctionProvider.php(89): civicrm_api3_contribution_repeattransaction((Array:6))
#25 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/Civi/API/Kernel.php(150): Civi\API\Provider\MagicFunctionProvider->invoke((Array:8))
#26 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/Civi/API/Kernel.php(81): Civi\API\Kernel->runRequest((Array:8))
#27 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/api/api.php(131): Civi\API\Kernel->runSafe("Contribution", "repeattransaction", (Array:5))
#28 /var/www/webadmin/data/www/secure.acme.org/sites/default/files/civicrm_extensions/com.iatspayments.civicrm/CRM/Iats/Transaction.php(128): civicrm_api3("Contribution", "repeattransaction", (Array:5))
#29 /var/www/webadmin/data/www/secure.acme.org/sites/default/files/civicrm_extensions/com.iatspayments.civicrm/api/v3/Job/Iatsrecurringcontributions.php(243): CRM_Iats_Transaction::process_contribution_payment((Array:20), (Array:17), (Array:6))
#30 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/Civi/API/Provider/MagicFunctionProvider.php(89): civicrm_api3_job_Iatsrecurringcontributions((Array:1))
#31 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/Civi/API/Kernel.php(150): Civi\API\Provider\MagicFunctionProvider->invoke((Array:8))
#32 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/Civi/API/Kernel.php(81): Civi\API\Kernel->runRequest((Array:8))
#33 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/api/api.php(22): Civi\API\Kernel->runSafe("Job", "iatsrecurringcontributions", (Array:1))
#34 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/CRM/Core/JobManager.php(133): civicrm_api("Job", "iatsrecurringcontributions", (Array:1))
#35 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/CRM/Core/JobManager.php(92): CRM_Core_JobManager->executeJob(Object(CRM_Core_ScheduledJob))
#36 /var/www/webadmin/data/www/secure.acme.org/sites/all/modules/civicrm/bin/cron.php(37): CRM_Core_JobManager->executeJobByAction("job", "iatsrecurringcontributions")
#37 {main}

May 19 02:38:44  [info] Retrying after Database lock encountered hit on attempt 2 at query : INSERT INTO `civicrm_contribution` (`contact_id` , `financial_type_id` , `payment_instrument_id` , `receive_date` , `total_amount` , `fee_amount` , `net_amount` , `currency` , `source` , `contribution_recur_id` , `is_test` , `contribution_status_id` , `check_number` , `campaign_id` ) VALUES ( 116272 ,  47 ,  2 ,  20210519023702 ,  100.00 ,  0 ,  100 , 'USD' , 'iATS Payments (iATSServiceACHEFT) Recurring Contribution ( id = 5146 )' ,  5146 ,  0 ,  2 ,  NULL ,  11 ) 

May 19 02:39:35  [error] $Fatal Error Details = Array
(
    [callback] => Array
        (
            [0] => CRM_Core_Error
            [1] => exceptionHandler
        )

    [code] => -30
    [message] => DB Error: database lock timeout
    [mode] => 16
    [debug_info] => INSERT INTO `civicrm_contribution` (`contact_id` , `financial_type_id` , `payment_instrument_id` , `receive_date` , `total_amount` , `fee_amount` , `net_amount` , `currency` , `source` , `contribution_recur_id` , `is_test` , `contribution_status_id` , `check_number` , `campaign_id` ) VALUES ( 116272 ,  47 ,  2 ,  20210519023702 ,  100.00 ,  0 ,  100 , 'USD' , 'iATS Payments (iATSServiceACHEFT) Recurring Contribution ( id = 5146 )' ,  5146 ,  0 ,  2 ,  NULL ,  11 )  [nativecode=1205 ** Lock wait timeout exceeded; try restarting transaction]
    [type] => DB_Error
    [user_info] => INSERT INTO `civicrm_contribution` (`contact_id` , `financial_type_id` , `payment_instrument_id` , `receive_date` , `total_amount` , `fee_amount` , `net_amount` , `currency` , `source` , `contribution_recur_id` , `is_test` , `contribution_status_id` , `check_number` , `campaign_id` ) VALUES ( 116272 ,  47 ,  2 ,  20210519023702 ,  100.00 ,  0 ,  100 , 'USD' , 'iATS Payments (iATSServiceACHEFT) Recurring Contribution ( id = 5146 )' ,  5146 ,  0 ,  2 ,  NULL ,  11 )  [nativecode=1205 ** Lock wait timeout exceeded; try restarting transaction]
    [to_string] => [db_error: message="DB Error: database lock timeout" code=-30 mode=callback callback=CRM_Core_Error::exceptionHandler prefix="" info="INSERT INTO `civicrm_contribution` (`contact_id` , `financial_type_id` , `payment_instrument_id` , `receive_date` , `total_amount` , `fee_amount` , `net_amount` , `currency` , `source` , `contribution_recur_id` , `is_test` , `contribution_status_id` , `check_number` , `campaign_id` ) VALUES ( 116272 ,  47 ,  2 ,  20210519023702 ,  100.00 ,  0 ,  100 , 'USD' , 'iATS Payments (iATSServiceACHEFT) Recurring Contribution ( id = 5146 )' ,  5146 ,  0 ,  2 ,  NULL ,  11 )  [nativecode=1205 ** Lock wait timeout exceeded; try restarting transaction]"]
)
adixon commented 3 years ago

Thanks for posting this. We've improved the error handling in the past few years, but you've found another way to break it!

For sure, the Database lock is the key error here, and your hypothesis about the sumfields extension seems reasonable.

cmmadmin commented 3 years ago

@adixon @KarinG I have completely disabled the Summary Fields extension.

To prevent this from ever occurring is it possible to mark a recurring contribution as 'In Progress' or 'Pending' or something so that it will not repeat the next day if no response is received from iATS (due to a db lock or some other catastrophic server issue)?

KarinG commented 3 years ago

@cmmadmin - that's exactly what the code is trying to do in the example you gave: contribution_status_id = 2 (Pending) and this fails as the tables are locked (presumably by summary fields extension).

To only run Summary Fields quarterly -> you can disable the Job and hit Execute now on it (Manually) 4x per year. Then you never risk that it will reset to its defaults (which sounds like it's hourly) and start producing conflicts with other Jobs (like the recurring contribution processing).

May 19 02:37:53  [info] Retrying after Database lock encountered hit on attempt 1 at query : INSERT INTO `civicrm_contribution` (`contact_id` , `financial_type_id` , `payment_instrument_id` , `receive_date` , `total_amount` , `fee_amount` , `net_amount` , `currency` , `source` , `contribution_recur_id` , `is_test` , `contribution_status_id` , `check_number` , `campaign_id` ) VALUES ( 116272 ,  47 ,  2 ,  20210519023702 ,  100.00 ,  0 ,  100 , 'USD' , 'iATS Payments (iATSServiceACHEFT) Recurring Contribution ( id = 5146 )' ,  5146 ,  0 ,  2 ,  NULL ,  11 ) 
cmmadmin commented 3 years ago

@KarinG Thanks for your response. That makes sense.

At what point in the process does the IATS extension attempt to set the contribution_status_id to 2 (Pending)?

Perhaps, it should attempt to do this prior to sending the request to IATS and if it fails then do not proceed to send the command to IATs. Seems like this would prevent the contribution from being processed twice wouldn't it?

-Malachi

cmmadmin commented 3 years ago

At a minimum would it be possible to add a feature to notify us by email when recurring contributions fail for any reason. We would want the email to include a list of the contributions that failed.

KarinG commented 3 years ago

The problem is that the recurring contribution actually does not fail - it succeeds (money is captured) but when the code is trying to create the contribution record for it on your CiviCRM - the table it needs access to is locked. And that is the root of the problem.

I've only helped out one project that uses Summary Fields extension and that was quite intense - jobs take a long time to run on a busy / extensive db. Staff was unable to do anything in their CiviCRM during the day until I isolated the problem and moved their Summary Fields extension job to a designated cron to run once during a designated window during the night. And by that I mean -> Disable the job in the CiviCRM UI - Scheduled Jobs and instead call it specifically via a crontab. If you do that for both the Recurring Contributions job and for Summary Fields job then you can clearly separate them to ensure they can not collide anymore. The additional benefit is that frequency can't switch back unexpectedly to defaults (like what happened in your case) - and there is no drift. That cron will run e.g. 3am exactly every night.

What exactly that looks like depends on how you run crons on your site (and whether it's a Drupal or Wordpress, etc.) -> -> https://docs.civicrm.org/sysadmin/en/latest/setup/jobs/

Example from one of our clients: iATS Recurring runs at 5am every day ->

# apache crontab for drupal/civicrm
0 5 * * * /usr/bin/php /usr/local/bin/drush-7/vendor/bin/drush.php --root='/var/www/platform/example/' --uri='https://example.org' -u 1 civicrm-api job.iatsrecurringcontributions auth=0 -y

And when checking their Contributions generated last night -> note the time: 5:01am image

cmmadmin commented 3 years ago

I was thinking of something like this, but perhaps there are other issues with this approach. This is pseudocode.

forall recur_contributions where (contribution_status_id != Attempting and != Pending) {
  dbresult = SetContributionStatusId = Attempting
  if (dbresult == success) {
    result = SendRequestToiATS()
    if (result == success) {
      SetContributionStatusId = Pending
    } else {
      notifyUserByEmail("iATS Contribution Error")
      SetContributionStatusId = Failed
    }
  } else {
    notifyUserByEmail("Civi Database Error")
  }
}