Recover transient Syncthing and SQLite job failures
This commit is contained in:
+39
-1
@@ -12,7 +12,7 @@ from archive_clients.jobs import (
|
||||
JobExecutionError,
|
||||
_resource_fingerprint,
|
||||
)
|
||||
from archive_clients.syncthing import RouteSetupError
|
||||
from archive_clients.syncthing import RouteSetupError, SyncthingTransferStatus
|
||||
from archive_clients.resources import normalize_resource
|
||||
from archive_clients.state import ClientStore
|
||||
from archive_control.v1 import control_pb2, job_pb2
|
||||
@@ -39,6 +39,44 @@ class SlowRescanSyncthing(CompleteSyncthing):
|
||||
|
||||
|
||||
class ClientJobHappyPathTests(unittest.TestCase):
|
||||
def test_syncthing_api_outage_during_transfer_is_retried(self):
|
||||
"""A transient local REST outage must not terminally fail the job."""
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
root = Path(directory)
|
||||
store = ClientStore(root / "client.db")
|
||||
store.initialize()
|
||||
definition = job_pb2.JobDefinition(
|
||||
job_id=str(uuid4()),
|
||||
transfer={
|
||||
"source_client_id": "cache-1",
|
||||
"target_client_id": "archive-1",
|
||||
"route_id": "route-1",
|
||||
},
|
||||
)
|
||||
observer = Mock()
|
||||
observer.status.side_effect = [
|
||||
RouteSetupError("Syncthing API is unavailable"),
|
||||
SyncthingTransferStatus(1, 42, 42, True, 0),
|
||||
]
|
||||
executor = ClientJobExecutor(
|
||||
client_id="archive-1",
|
||||
qbittorrent=Mock(),
|
||||
store=store,
|
||||
qb_root=root,
|
||||
qb_api_root=Path("/downloads"),
|
||||
route_path=lambda _: root,
|
||||
syncthing_transport=Mock(),
|
||||
sparse_supported=True,
|
||||
poll_interval=0,
|
||||
)
|
||||
executor._observer = Mock(return_value=observer)
|
||||
progress = Mock()
|
||||
|
||||
executor._wait_for_syncthing(definition, progress)
|
||||
|
||||
self.assertEqual(observer.status.call_count, 2)
|
||||
progress.assert_called_once_with(1, 42, 42, "0 Syncthing items still needed")
|
||||
|
||||
def test_reconnect_replay_never_duplicates_any_transfer_step(self):
|
||||
for step in (
|
||||
job_pb2.JOB_STEP_KIND_SOURCE_STAGE,
|
||||
|
||||
Reference in New Issue
Block a user