From b7ee37bb0aa77e7e5d0573995b7f3e3ddcef097c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 27 Oct 2025 19:20:23 +0100 Subject: [PATCH] Replace clean_days with log_size in the cron configuration Closes #14319 --- trytond/CHANGELOG | 1 + trytond/doc/topics/configuration.rst | 8 +++--- trytond/trytond/ir/cron.py | 39 +++++++++++++++++++++++----- trytond/trytond/tests/test_ir.py | 21 +++++++++++++++ 4 files changed, 58 insertions(+), 11 deletions(-) diff --git a/trytond/CHANGELOG b/trytond/CHANGELOG index 0f0e639bc8..40bc524d79 100644 --- a/trytond/CHANGELOG +++ b/trytond/CHANGELOG @@ -1,3 +1,4 @@ +* Replace ``clean_days`` with ``log_size`` in the cron configuration * Enforce access check in export_data (issue14366) * Include the traceback only in RPC responses in development mode (issue14354) * Enforce access check in HTML editor route (issue14364) diff --git a/trytond/doc/topics/configuration.rst b/trytond/doc/topics/configuration.rst index 211735728e..cb886eed7f 100644 --- a/trytond/doc/topics/configuration.rst +++ b/trytond/doc/topics/configuration.rst @@ -447,12 +447,12 @@ cron .. _config-cron.clean_days: -clean_days -~~~~~~~~~~ +log_size +~~~~~~~~ -The number of days after which scheduled task logs are removed. +The approximate number of log entries to keep for each scheduled task. -Default: ``30`` +Default: ``100`` .. _config-queue: diff --git a/trytond/trytond/ir/cron.py b/trytond/trytond/ir/cron.py index ca84f534a9..c90a2668da 100644 --- a/trytond/trytond/ir/cron.py +++ b/trytond/trytond/ir/cron.py @@ -9,7 +9,8 @@ from collections import defaultdict from dateutil.relativedelta import relativedelta from sql import Literal -from sql.conditionals import Coalesce +from sql.conditionals import Case, Coalesce +from sql.functions import CurrentTimestamp, Extract from trytond import backend, config from trytond.exceptions import UserError, UserWarning @@ -311,10 +312,34 @@ class Log(ModelSQL, ModelView): return self.ended - self.started @classmethod - def clean(cls, date=None): - if date is None: - clean_days = config.getint('cron', 'clean_days', default=30) - date = ( - datetime.datetime.now() - datetime.timedelta(days=clean_days)) - logs = cls.search([('create_date', '<', date)]) + def clean(cls, size=None): + pool = Pool() + Cron = pool.get('ir.cron') + cursor = Transaction().connection.cursor() + + log = cls.__table__() + cron = Cron.__table__() + + if size is None: + size = config.getint('cron', 'log_size', default=100) + + interval = Case( + (cron.interval_type == 'minutes', datetime.timedelta(minutes=1)), + (cron.interval_type == 'hours', datetime.timedelta(hours=1)), + (cron.interval_type == 'days', datetime.timedelta(days=1)), + (cron.interval_type == 'weeks', datetime.timedelta(weeks=1)), + (cron.interval_type == 'months', datetime.timedelta(days=30))) + + started = log.started + now = CurrentTimestamp() + if backend.name == 'sqlite': + started = Extract('epoch', started) + now = Extract('epoch', now) + + cursor.execute(*log + .join(cron, condition=log.cron == cron.id) + .select(log.id, + where=started < ( + now - (interval * cron.interval_number * size)))) + logs = cls.browse([l for l, in cursor]) cls.delete(logs) diff --git a/trytond/trytond/tests/test_ir.py b/trytond/trytond/tests/test_ir.py index d01943d8f7..6c0b29223f 100644 --- a/trytond/trytond/tests/test_ir.py +++ b/trytond/trytond/tests/test_ir.py @@ -802,5 +802,26 @@ class IrCronTestCase(TestCase): self.assertIsInstance(cron.get_timezone('timezone'), str) + @with_transaction() + def test_clean(self): + "Test cleaning cron logs" + pool = Pool() + Cron = pool.get('ir.cron') + Log = pool.get('ir.cron.log') + dt = datetime + + cron = Cron( + interval_number=2, interval_type='hours', + method='ir.trigger|trigger_time') + cron.logs = [{ + 'started': dt.datetime.now() - dt.timedelta(hours=i), + 'ended': dt.datetime.now() - dt.timedelta(hours=i + 1)} + for i in range(0, 20, 2)] + cron.save() + + Log.clean(5) + + self.assertEqual(len(cron.logs), 5) + del ModuleTestCase