Bug 41603

Summary: Plugin hook causing DB locks when cancelling holds
Product: Koha Reporter: Tomás Cohen Arazi (tcohen) <tomascohen>
Component: Plugin architectureAssignee: Tomás Cohen Arazi (tcohen) <tomascohen>
Status: NEW --- QA Contact: Testopia <testopia>
Severity: critical    
Priority: P5 - low CC: tomascohen
Version: Main   
Hardware: All   
OS: All   
GIT URL: Initiative type: ---
Sponsorship status: --- Comma delimited list of Sponsors:
Crowdfunding goal: 0 Patch complexity: ---
Documentation contact: Documentation submission:
Text to go in the release notes:
Version(s) released in:
Circulation function:

Description Tomás Cohen Arazi (tcohen) 2026-01-13 15:42:52 UTC
The Rapido ILL plugin [1] has a simple `after_hold_action` hook that checks if the current hold is linked to an ILL request [2], and in the positive case, it inserts a row on a `task_queue` table for the action to be processed asynchronously by a separate daemon/worker.

Even though the plugin itself is not doing any heavy action on the DB, this causes DB locks that are easily reproducible. This seems to be a core Koha issue as it makes the holds cancelling process (and probably others) rather fragile.

To reproduce:
1. Clone Rapido ILL:
   $ mkdir -p ~/git/koha-plugins && cd ~/git/koha-plugins
   $ git clone https://github.com/bywatersolutions/koha-plugin-rapido-ill.git rapido-ill
2. Start a KTD instance:
   $ ktd --proxy --name rapido --single-plugin ~/git/koha-plugins/rapido-ill up -d
   $ ktd --name rapido --wait-ready 200
3. Install the plugin config
   $ ktd --name rapido --shell
  k$ cd /kohadevbox/plugins/rapido-ill/scripts
  k$ perl bootstrap_rapido_testing.pl
  k$ restart_all
4. Create a hold for a known patron
5. Run this:
  k$ perl -e 'use Carp::Always; use Koha::Holds; my $hold = Koha::Holds->find(1);$hold->cancel({cancellation_reason => "OVER_365"})'
=> FAIL: It takes a while! It eventually fails with a lock wait timeout!:

```
C4::Reserves::_FixPriority(): DBI Exception: DBD::mysql::st execute failed: Lock wait timeout exceeded; try restarting transaction at /kohadevbox/koha/Koha/Hold.pm line 933
```

=> FACTS: There's a hold, being cancelled. There is no ILL request on the system. The only thing that is happening is that the plugin hook is being called, and is doing this query:

```
MariaDB [koha_cuyahoga]> SELECT me.*
    FROM illrequests me
    JOIN illrequestattributes
    ON illrequestattributes.illrequest_id = me.illrequest_id
    WHERE illrequestattributes.type = 'hold_id'
    AND illrequestattributes.value = '1'
    AND me.backend = 'RapidoILL';
Empty set (0.001 sec)
```

Moving the plugin hook outside the transaction fixes it.

[1] https://github.com/bywatersolutions/koha-plugin-rapido-ill
[2] Linked means checking if it has an extended attribute with the hold_id value. No FK checks.