Skip to content

Commit c87991c

Browse files
dgarciabrisenoDaniel Garcia Briseno
andauthored
Prevent localmove.py from excess logging (#471)
Co-authored-by: Daniel Garcia Briseno <daniel.garciabriseno@nasa.gov>
1 parent 188556c commit c87991c

2 files changed

Lines changed: 80 additions & 6 deletions

File tree

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
"""Tests for LocalFileMove retry limit functionality"""
2+
import unittest
3+
from unittest.mock import patch, MagicMock
4+
from queue import Queue
5+
6+
from helioviewer.hvpull.downloader.localmove import LocalFileMove, MAX_RETRY_ATTEMPTS
7+
8+
9+
class TestLocalFileMoveRetry(unittest.TestCase):
10+
"""Test that file move retries are limited to MAX_RETRY_ATTEMPTS"""
11+
12+
def setUp(self):
13+
self.queue = Queue()
14+
self.mover = LocalFileMove("/tmp/incoming", self.queue)
15+
16+
@patch('shutil.move')
17+
@patch('os.path.exists', return_value=True)
18+
def test_successful_move_does_not_retry(self, mock_exists, mock_move):
19+
"""A successful move should not add anything to the queue"""
20+
self.mover.process(["server1", 100, "/source/file.jp2"])
21+
22+
mock_move.assert_called_once()
23+
self.assertTrue(self.queue.empty())
24+
25+
@patch('shutil.move', side_effect=IOError("File busy"))
26+
@patch('os.path.exists', return_value=True)
27+
def test_failed_move_retries_up_to_max(self, mock_exists, mock_move):
28+
"""A failing move should retry MAX_RETRY_ATTEMPTS times then give up"""
29+
# First attempt (retry_count=0)
30+
self.mover.process(["server1", 100, "/source/file.jp2"])
31+
32+
# Should be re-queued with retry_count=1
33+
self.assertEqual(self.queue.qsize(), 1)
34+
item = self.queue.get()
35+
self.assertEqual(item[3], 1) # retry_count = 1
36+
37+
# Second attempt (retry_count=1)
38+
self.mover.process(item)
39+
item = self.queue.get()
40+
self.assertEqual(item[3], 2) # retry_count = 2
41+
42+
# Third attempt (retry_count=2)
43+
self.mover.process(item)
44+
item = self.queue.get()
45+
self.assertEqual(item[3], 3) # retry_count = 3
46+
47+
# Fourth attempt (retry_count=3) - should give up, not re-queue
48+
self.mover.process(item)
49+
self.assertTrue(self.queue.empty(), "Should not retry after MAX_RETRY_ATTEMPTS")
50+
51+
def test_max_retry_attempts_is_three(self):
52+
"""Verify the constant is set to 3"""
53+
self.assertEqual(MAX_RETRY_ATTEMPTS, 3)
54+
55+
56+
if __name__ == '__main__':
57+
unittest.main()

install/helioviewer/hvpull/downloader/localmove.py

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
import shutil
77
from .downloader_interface import Downloader
88

9+
# Maximum number of retry attempts per file before giving up
10+
MAX_RETRY_ATTEMPTS = 3
11+
912
class LocalFileMove(Downloader):
1013
def __init__(self, incoming, queue):
1114
"""Creates a new LocalFileMover"""
@@ -16,9 +19,17 @@ def __init__(self, incoming, queue):
1619
# self.queue
1720

1821
def process(self, item):
19-
"""Downloads the file at the specified URI"""
20-
#ValueError: too many values to unpack
21-
server, percent, uri = item
22+
"""Downloads the file at the specified URI
23+
24+
Item format: [server, percent, uri] or [server, percent, uri, retry_count]
25+
The retry_count is optional and defaults to 0 for backward compatibility.
26+
"""
27+
# Support both old format (3 elements) and new format (4 elements with retry count)
28+
if len(item) == 3:
29+
server, percent, uri = item
30+
retry_count = 0
31+
else:
32+
server, percent, uri, retry_count = item
2233

2334
# @TODO: compute path to download file to...
2435

@@ -38,8 +49,14 @@ def process(self, item):
3849
t2 = time.time()
3950
logging.info("(%s) locally moved %s to %s", server, uri, filepath)
4051
except IOError:
41-
# If download fails, add back into queue and try again later
42-
logging.warning("Failed to move %s. Adding to end of queue to retry later.", uri)
43-
self.queue.put([server, percent, uri])
52+
# If move fails, check retry count before re-queuing
53+
if retry_count < MAX_RETRY_ATTEMPTS:
54+
retry_count += 1
55+
logging.warning("Failed to move %s. Adding to end of queue to retry later (attempt %d/%d).",
56+
uri, retry_count, MAX_RETRY_ATTEMPTS)
57+
self.queue.put([server, percent, uri, retry_count])
58+
else:
59+
logging.error("Failed to move %s after %d attempts. Giving up on this file.",
60+
uri, MAX_RETRY_ATTEMPTS)
4461
except:
4562
logging.warning("Failed to move %s.", uri)

0 commit comments

Comments
 (0)