From 490ff41cdc3636bcbbb67e098070c8a473cd3a76 Mon Sep 17 00:00:00 2001 From: Walter Boring Date: Fri, 27 Mar 2026 17:37:16 -0400 Subject: [PATCH] feat: Add configurable stats_store_interval for stats file saves Add stats_store_interval config option to control how frequently the statsstore.json file is written to disk. Default remains 10 seconds for backward compatibility. This allows reducing disk I/O in production deployments and can help avoid potential file corruption issues when external processes read the stats file. --- aprsd/conf/common.py | 6 ++++++ aprsd/threads/stats.py | 3 ++- tests/threads/test_stats.py | 19 ++++++++++++++----- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/aprsd/conf/common.py b/aprsd/conf/common.py index f51eb22..b7595b6 100644 --- a/aprsd/conf/common.py +++ b/aprsd/conf/common.py @@ -133,6 +133,12 @@ aprsd_opts = [ help='Enable the Callsign seen list tracking feature. This allows aprsd to keep track of ' 'callsigns that have been seen and when they were last seen.', ), + cfg.IntOpt( + 'stats_store_interval', + default=10, + help='Interval in seconds between stats file saves to disk. ' + 'Lower values provide more frequent updates but increase disk I/O.', + ), cfg.BoolOpt( 'enable_packet_logging', default=True, diff --git a/aprsd/threads/stats.py b/aprsd/threads/stats.py index 91eb00c..e5fd23f 100644 --- a/aprsd/threads/stats.py +++ b/aprsd/threads/stats.py @@ -32,10 +32,11 @@ class APRSDStatsStoreThread(APRSDThread): """Save APRSD Stats to disk periodically.""" daemon = False - period = 10 def __init__(self): super().__init__('StatsStore') + # Use config value for period, default to 10 seconds + self.period = CONF.stats_store_interval def loop(self): stats = collector.Collector().collect() diff --git a/tests/threads/test_stats.py b/tests/threads/test_stats.py index d23fa3b..79d0bac 100644 --- a/tests/threads/test_stats.py +++ b/tests/threads/test_stats.py @@ -72,11 +72,20 @@ class TestAPRSDStatsStoreThread(unittest.TestCase): def test_init(self): """Test APRSDStatsStoreThread initialization.""" - thread = APRSDStatsStoreThread() - self.assertEqual(thread.name, 'StatsStore') - self.assertEqual(thread.period, 10) - self.assertFalse(thread.daemon) - self.assertTrue(hasattr(thread, 'loop_count')) + with mock.patch('aprsd.threads.stats.CONF') as mock_conf: + mock_conf.stats_store_interval = 10 + thread = APRSDStatsStoreThread() + self.assertEqual(thread.name, 'StatsStore') + self.assertEqual(thread.period, 10) + self.assertFalse(thread.daemon) + self.assertTrue(hasattr(thread, 'loop_count')) + + def test_init_with_custom_interval(self): + """Test APRSDStatsStoreThread uses stats_store_interval from config.""" + with mock.patch('aprsd.threads.stats.CONF') as mock_conf: + mock_conf.stats_store_interval = 60 + thread = APRSDStatsStoreThread() + self.assertEqual(thread.period, 60) def test_loop_with_save(self): """Test loop method saves stats every call."""