Alert Improvements by Xon

Alert Improvements by Xon 2.14.4

No permission to download
I have loads of these:

  • XF\Db\Exception: SV\AlertImprovements\Job\AlertTotalRebuild: MySQL query error [1205]: Lock wait timeout exceeded; try restarting transaction
  • src/XF/Db/AbstractStatement.php:225
  • Generated by: Unknown account
    Mar 7, 2026 at 8:25 AM

Stack trace​


DELETE pendingRebuild
FROM xf_sv_user_alert_rebuild AS pendingRebuild
LEFT JOIN xf_user ON xf_user.user_id = pendingRebuild.user_id
WHERE xf_user.user_id IS NULL

------------

#0 src/XF/Db/Mysqli/Statement.php(207): XF\Db\AbstractStatement->getException('MySQL query err...', 1205, 'HY000')
#1 src/XF/Db/Mysqli/Statement.php(83): XF\Db\Mysqli\Statement->getException('MySQL query err...', 1205, 'HY000')
#2 src/XF/Db/AbstractAdapter.php(96): XF\Db\Mysqli\Statement->execute()
#3 src/addons/SV/AlertImprovements/Job/AlertTotalRebuild.php(52): XF\Db\AbstractAdapter->query('
...')
#4 src/XF/Db/AbstractAdapter.php(457): SV\AlertImprovements\Job\AlertTotalRebuild->SV\AlertImprovements\Job\{closure}(Object(XF\Db\Mysqli\Adapter))
#5 src/addons/SV/AlertImprovements/Job/AlertTotalRebuild.php(51): XF\Db\AbstractAdapter->executeTransaction(Object(Closure), 1)
#6 src/XF/Job/AbstractRebuildJob.php(53): SV\AlertImprovements\Job\AlertTotalRebuild->getNextIds(0, 100)
#7 src/XF/Job/Manager.php(275): XF\Job\AbstractRebuildJob->run(44.7942)
#8 src/XF/Job/Manager.php(205): XF\Job\Manager->runJobInternal(Array, 44.7942)
#9 src/XF/Job/Manager.php(89): XF\Job\Manager->runJobEntry(Array, 44.7942)
#10 src/XF/Cli/Command/RunJobs.php(58): XF\Job\Manager->runQueue(false, 45)
#11 src/vendor/symfony/console/Command/Command.php(298): XF\Cli\Command\RunJobs->execute(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#12 src/vendor/symfony/console/Application.php(1040): Symfony\Component\Console\Command\Command->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#13 src/vendor/symfony/console/Application.php(301): Symfony\Component\Console\Application->doRunCommand(Object(XF\Cli\Command\RunJobs), Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#14 src/vendor/symfony/console/Application.php(171): Symfony\Component\Console\Application->doRun(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#15 src/XF/Cli/Runner.php(115): Symfony\Component\Console\Application->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#16 cmd.php(17): XF\Cli\Runner->run()
#17 {main}

Request state​


array(1) {
["cli"] => string(62) "/cmd.php xf:run-jobs"
}
XF2.3.10
 
Last edited:
I have loads of these:

  • XF\Db\Exception: SV\AlertImprovements\Job\AlertTotalRebuild: MySQL query error [1205]: Lock wait timeout exceeded; try restarting transaction
  • src/XF/Db/AbstractStatement.php:225
  • Generated by: Unknown account
    Mar 7, 2026 at 8:25 AM
This happens when it is trying to prune the list pending user alert total rebuilds from on deleted users.

Can you report the result of this SQL query?
SQL:
select count(*) from xf_sv_user_alert_rebuild;

I'll also need to see the explain output too;
SQL:
explain
DELETE pendingRebuild
FROM xf_sv_user_alert_rebuild AS pendingRebuild
LEFT JOIN xf_user ON xf_user.user_id = pendingRebuild.user_id
WHERE xf_user.user_id IS NULL

You can work around this by truncating the table;
SQL:
truncate table xf_sv_user_alert_rebuild;
The next time it runs it should operate on fewer users.
 
select count(*) from xf_sv_user_alert_rebuild;
8
I'll also need to see the explain output too;
explain DELETE pendingRebuild FROM xf_sv_user_alert_rebuild AS pendingRebuild LEFT JOIN xf_user ON xf_user.user_id = pendingRebuild.user_id WHERE xf_user.user_id IS NULL
pendingRebuild: rows 8
xf_user: rows 1
ou can work around this by truncating the table;
truncate table xf_sv_user_alert_rebuild;The next time it runs it should operate on fewer users.
Done. Thanks!

This could be related to an issue in @Naz Tickets where users request account deletion in a ticket. The user is deleted and the ticket resolved. Alert goes to non-existent user.
 
This could be related to an issue in @Naz Tickets where users request account deletion in a ticket. The user is deleted and the ticket resolved. Alert goes to non-existent user.
That will be an issue for the Tickets add-on.

XF\Db\Exception: SV\AlertImprovements\Job\AlertTotalRebuild: MySQL query error [1205]: Lock wait timeout exceeded; try restarting transaction
Next version should properly prevent deadlocks in this code path, and makes the alert totals rebuild lighter weight
 
Xon updated Alert Improvements by Xon with a new update entry:

2.14.3 - Bugfix update

  • php 8.4+ compatibility fixes
  • Improve XF Cloud support
  • Fix alert summarizing blocks viewing alerts with "Please enter a number that is no more than 4294967295." when there are more the alert_id > 2^32
    This update runs the following schema change, which may take time.
    SQL:
     alter table xf_sv_user_alert_summary modify column alert_id bigint not null;
  • Fix xf_sv_user_alert_summary entries did not get cleaned up when alerts expired
  • Fix...

Read the rest of this update entry...
 
I have thousands of these now:
  • XF\Db\Exception: SV\AlertImprovements\Job\AlertTotalRebuild: MySQL query error [1205]: Lock wait timeout exceeded; try restarting transaction
  • src/XF/Db/AbstractStatement.php:225
  • Generated by: Unknown account
  • Mar 11, 2026 at 3:49 PM

Stack trace​


SELECT IF(is_banned, 'banned', user_state) FROM xf_user WHERE user_id = ? FOR UPDATE
------------

#0 src/XF/Db/Mysqli/Statement.php(207): XF\Db\AbstractStatement->getException('MySQL query err...', 1205, 'HY000')
#1 src/XF/Db/Mysqli/Statement.php(83): XF\Db\Mysqli\Statement->getException('MySQL query err...', 1205, 'HY000')
#2 src/XF/Db/AbstractAdapter.php(96): XF\Db\Mysqli\Statement->execute()
#3 src/XF/Db/AbstractAdapter.php(152): XF\Db\AbstractAdapter->query('SELECT IF(is_ba...', 466736)
#4 src/addons/SV/AlertImprovements/Job/AlertTotalRebuild.php(77): XF\Db\AbstractAdapter->fetchOne('SELECT IF(is_ba...', 466736)
#5 src/XF/Job/AbstractRebuildJob.php(65): SV\AlertImprovements\Job\AlertTotalRebuild->rebuildById(466736)
#6 src/XF/Job/Manager.php(275): XF\Job\AbstractRebuildJob->run(43.5154)
#7 src/XF/Job/Manager.php(205): XF\Job\Manager->runJobInternal(Array, 43.5154)
#8 src/XF/Job/Manager.php(89): XF\Job\Manager->runJobEntry(Array, 43.5154)
#9 src/XF/Cli/Command/RunJobs.php(58): XF\Job\Manager->runQueue(false, 45)
#10 src/vendor/symfony/console/Command/Command.php(298): XF\Cli\Command\RunJobs->execute(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#11 src/vendor/symfony/console/Application.php(1040): Symfony\Component\Console\Command\Command->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#12 src/vendor/symfony/console/Application.php(301): Symfony\Component\Console\Application->doRunCommand(Object(XF\Cli\Command\RunJobs), Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#13 src/vendor/symfony/console/Application.php(171): Symfony\Component\Console\Application->doRun(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#14 src/XF/Cli/Runner.php(115): Symfony\Component\Console\Application->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#15 cmd.php(17): XF\Cli\Runner->run()
#16 {main}

Request state​


array(1) {
["cli"] => string(62) "/cmd.php xf:run-jobs"
}
 
What the heck, that should be the most simple lock to hold, and these locks shouldn't be held for long! I'll do a review and see if I can shrink the transaction size.
 
Last edited:
@Alpha1 Please ensure your mysql server has this in a .cnf file;
Code:
innodb_print_all_deadlocks = 1

You can enable this dynamically with;
SQL:
set global innodb_print_all_deadlocks = 1

Then you can inspect your the mysql.log (or mariadb.log) file and report all the queries involved in the deadlock and the indexes involved. This will help massively in me determining what the compatibility issue is.
 
Back
Top Bottom