From 7ba7bbab7d74e557a834d55e0a9b6817ea9b8d79 Mon Sep 17 00:00:00 2001 From: Kyle M Hall Date: Wed, 25 Feb 2026 13:05:03 -0500 Subject: [PATCH] Bug 41920: Limit number of concurrent reports that can be run simultaneously for an instance of Koha As a continuation of bug 41919, we should limit the total number of simultaneous reports that can be run at a time. Test Plan: 1) Set total_running_reports_per_instance_limit to 2 in your koha-conf.xml 2) Create 3 long running reports like: SELECT COUNT(*) FROM items i1 JOIN items i2 JOIN items i3 JOIN items i4 JOIN items i5 JOIN items i6 3) Run each report in turn by opening a new tab, browsing to the reports module, and choosing to run that report 5) Note the first two continue to run, but the last one gives an error that you have too many reports running simultaneously! Signed-off-by: Alex Carver [Acerock7] Signed-off-by: Andrew Fuerste Henry Signed-off-by: Pedro Amorim --- Koha/Reports.pm | 3 +- debian/templates/koha-conf-site.xml.in | 1 + etc/koha-conf.xml | 1 + .../modules/reports/guided_reports_start.tt | 2 + reports/guided_reports.pl | 63 +++++++++++++++++++ 5 files changed, 69 insertions(+), 1 deletion(-) diff --git a/Koha/Reports.pm b/Koha/Reports.pm index 6e2f8f3974..e36bb464d3 100644 --- a/Koha/Reports.pm +++ b/Koha/Reports.pm @@ -103,7 +103,8 @@ sub running { $report_ids{$1} = 1 if $row->{info} =~ /saved_sql\.id:\s*(\d+)/; } - return $class->search( { id => { -in => [ keys %report_ids ] } } ); + my $rs = $class->search( { id => { -in => [ keys %report_ids ] } } ); + return wantarray ? $rs->as_list : $rs; } =head3 _processlist_rows diff --git a/debian/templates/koha-conf-site.xml.in b/debian/templates/koha-conf-site.xml.in index 03fffb6317..f31f6ea442 100644 --- a/debian/templates/koha-conf-site.xml.in +++ b/debian/templates/koha-conf-site.xml.in @@ -348,6 +348,7 @@ __END_SRU_PUBLICSERVER__ 0 0 + 0 diff --git a/etc/koha-conf.xml b/etc/koha-conf.xml index f811a0d378..9ba30b399a 100644 --- a/etc/koha-conf.xml +++ b/etc/koha-conf.xml @@ -165,6 +165,7 @@ 0 0 + 0 diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/reports/guided_reports_start.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/reports/guided_reports_start.tt index 40df265fce..166c8fac65 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/reports/guided_reports_start.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/reports/guided_reports_start.tt @@ -1714,6 +1714,8 @@

This report is already running. Please wait for it to finish before running it again.

[% ELSIF ( error.total_running_reports_limit_exceeded ) %]

You have too many reports running at the moment. Please wait for some of them to finish before running this report again.

+ [% ELSIF ( error.total_running_reports_per_instance_limit_exceeded ) %] +

There are too many total reports running at the moment. Please wait for some of them to finish before running this report again.

[% ELSIF ( error.sqlerr ) %]

This report contains an SQL keyword: [% error.sqlerr | html %].

Use of this keyword is not allowed in Koha reports due to security and data integrity risks. Only SELECT queries are allowed.

diff --git a/reports/guided_reports.pl b/reports/guided_reports.pl index 8b9f72ec4e..2a4132b7fa 100755 --- a/reports/guided_reports.pl +++ b/reports/guided_reports.pl @@ -885,6 +885,42 @@ if ( $op eq 'run' ) { my $template_code = $input->param('template_code'); my $want_full_chart = $input->param('want_full_chart') || 0; + # Determine if the user is running this report too many times + my @duplicate_running_report_ids; + my $duplicate_running_reports_per_user_limit = C4::Context->config('duplicate_running_reports_per_user_limit'); + if ( $duplicate_running_reports_per_user_limit && C4::Context->userenv ) { + my $user_id = C4::Context->userenv ? C4::Context->userenv->{number} : undef; + @duplicate_running_report_ids = Koha::Reports->running( { report_id => $report_id, user_id => $user_id } ); + } + my $duplicate_running_reports_per_user_limit_exceeded = + $duplicate_running_reports_per_user_limit + ? scalar(@duplicate_running_report_ids) >= $duplicate_running_reports_per_user_limit + : 0; + + # Determine if the user is running too many reports in total + my @total_running_for_user_report_ids; + my $total_running_reports_per_user_limit = C4::Context->config('total_running_reports_per_user_limit'); + if ( $total_running_reports_per_user_limit && C4::Context->userenv ) { + my $user_id = C4::Context->userenv ? C4::Context->userenv->{number} : undef; + @total_running_for_user_report_ids = Koha::Reports->running( { user_id => $user_id } ); + } + my $total_running_reports_per_user_limit_exceeded = + $total_running_reports_per_user_limit + ? scalar(@total_running_for_user_report_ids) >= $total_running_reports_per_user_limit + : 0; + + # Determine if the Koha instance is running too many reports in total + my @total_running_for_instance_report_ids; + my $total_running_reports_per_instance_limit = C4::Context->config('total_running_reports_per_instance_limit'); + if ( $total_running_reports_per_instance_limit && C4::Context->userenv ) { + my $instance_id = C4::Context->userenv ? C4::Context->userenv->{number} : undef; + @total_running_for_instance_report_ids = Koha::Reports->running(); + } + my $total_running_reports_per_instance_limit_exceeded = + $total_running_reports_per_instance_limit + ? scalar(@total_running_for_instance_report_ids) >= $total_running_reports_per_instance_limit + : 0; + # offset algorithm if ( $input->param('page') ) { $offset = ( $input->param('page') - 1 ) * $limit; @@ -1070,6 +1106,33 @@ if ( $op eq 'run' ) { 'id' => $report_id, 'template_code' => $template_code, ); + } elsif ( $duplicate_running_reports_per_user_limit_exceeded + || $total_running_reports_per_user_limit_exceeded + || $total_running_reports_per_instance_limit_exceeded ) + { + $template->param( + 'sql' => $sql, + 'original_sql' => $original_sql, + 'id' => $report_id, + 'execute' => 1, + 'name' => $name, + 'notes' => $notes, + 'errors' => [ + $duplicate_running_reports_per_user_limit_exceeded + ? { duplicate_running_report_ids => \@duplicate_running_report_ids } + : (), + $total_running_reports_per_user_limit_exceeded + ? { total_running_reports_per_user_limit_exceeded => \@total_running_for_user_report_ids } + : (), + $total_running_reports_per_instance_limit_exceeded + ? { + total_running_reports_per_instance_limit_exceeded => \@total_running_for_instance_report_ids + } + : (), + ], + 'sql_params' => \@sql_params, + 'param_names' => \@param_names, + ); } else { my ( $sql, $header_types ); eval { ( $sql, $header_types ) = $report->prep_report( \@param_names, \@sql_params ); };