Skip to content

Commit ffcbdae

Browse files
authored
Catch Send/Receive errors and make them sync errors (#1924)
LfMergeBridgeResult instances now contain ErrorEncountered property, passed through to the IProgress instance they wrap.
1 parent 678817f commit ffcbdae

3 files changed

Lines changed: 102 additions & 4 deletions

File tree

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
using SIL.Progress;
2+
3+
namespace FwHeadless.Services;
4+
5+
public class CombiningProgress(params ICollection<IProgress?> progresses) : IProgress
6+
{
7+
8+
public bool ShowVerbose
9+
{
10+
set { foreach (var p in progresses) { if (p is not null) p.ShowVerbose = value; } }
11+
}
12+
13+
public bool CancelRequested
14+
{
15+
get => progresses.Any(p => p?.CancelRequested ?? false);
16+
set { foreach (var p in progresses) { if (p is not null) p.CancelRequested = value; } }
17+
}
18+
19+
public bool ErrorEncountered
20+
{
21+
get => progresses.Any(p => p?.ErrorEncountered ?? false);
22+
set { foreach (var p in progresses) { if (p is not null) p.ErrorEncountered = value; } }
23+
}
24+
25+
public IProgressIndicator ProgressIndicator
26+
{
27+
get => progresses.FirstOrDefault(p => p?.ProgressIndicator is not null)?.ProgressIndicator ?? null!;
28+
set { foreach (var p in progresses) { if (p is not null) p.ProgressIndicator = value; } }
29+
}
30+
31+
public SynchronizationContext SyncContext
32+
{
33+
get => progresses.FirstOrDefault(p => p?.SyncContext is not null)?.SyncContext ?? null!;
34+
set { foreach (var p in progresses) { if (p is not null) p.SyncContext = value; } }
35+
}
36+
37+
public void WriteError(string message, params object[] args)
38+
{
39+
foreach (var p in progresses) { p?.WriteError(message, args); }
40+
}
41+
42+
public void WriteException(Exception error)
43+
{
44+
foreach (var p in progresses) { p?.WriteException(error); }
45+
}
46+
47+
public void WriteMessage(string message, params object[] args)
48+
{
49+
foreach (var p in progresses) { p?.WriteMessage(message, args); }
50+
}
51+
52+
public void WriteMessageWithColor(string colorName, string message, params object[] args)
53+
{
54+
foreach (var p in progresses) { p?.WriteMessageWithColor(colorName, message, args); }
55+
}
56+
57+
public void WriteStatus(string message, params object[] args)
58+
{
59+
foreach (var p in progresses) { p?.WriteStatus(message, args); }
60+
}
61+
62+
public void WriteVerbose(string message, params object[] args)
63+
{
64+
foreach (var p in progresses) { p?.WriteVerbose(message, args); }
65+
}
66+
67+
public void WriteWarning(string message, params object[] args)
68+
{
69+
foreach (var p in progresses) { p?.WriteWarning(message, args); }
70+
}
71+
}

backend/FwHeadless/Services/SendReceiveHelpers.cs

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
namespace FwHeadless.Services;
66

7+
public class SendReceiveException(string? message) : Exception(message);
8+
79
public static class SendReceiveHelpers
810
{
911
private const string HgUsername = "FieldWorks Lite";
@@ -17,17 +19,26 @@ public record SendReceiveAuth(string Username, string Password)
1719
public SendReceiveAuth(FwHeadlessConfig config) : this(config.LexboxUsername, config.LexboxPassword) { }
1820
};
1921

20-
public record LfMergeBridgeResult(string Output, string ProgressMessages);
22+
public record LfMergeBridgeResult(string Output)
23+
{
24+
private readonly IProgress? _progress = null;
25+
public bool ErrorEncountered => _progress?.ErrorEncountered ?? false;
26+
public LfMergeBridgeResult(string output, IProgress progress) : this(output)
27+
{
28+
_progress = progress;
29+
}
30+
}
2131

2232
private static async Task<LfMergeBridgeResult> CallLfMergeBridge(string method, IDictionary<string, string> flexBridgeOptions, IProgress? progress = null)
2333
{
2434
var sbProgress = new StringBuilderProgress();
35+
var combinedProgress = new CombiningProgress(sbProgress, progress);
2536
var lfMergeBridgeOutputForClient = await Task.Run(() =>
2637
{
27-
LfMergeBridge.LfMergeBridge.Execute(method, progress ?? sbProgress, flexBridgeOptions.ToDictionary(), out var output);
38+
LfMergeBridge.LfMergeBridge.Execute(method, combinedProgress, flexBridgeOptions.ToDictionary(), out var output);
2839
return output;
2940
});
30-
return new LfMergeBridgeResult(lfMergeBridgeOutputForClient, progress == null ? sbProgress.ToString() : "");
41+
return new LfMergeBridgeResult(lfMergeBridgeOutputForClient, sbProgress);
3142
}
3243

3344
private static Uri BuildSendReceiveUrl(string baseUrl, string projectCode, SendReceiveAuth? auth, bool forChorus = true)

backend/FwHeadless/Services/SyncHostedService.cs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,15 @@ public async Task<SyncJobResult> ExecuteSync(CancellationToken stoppingToken)
144144
logger.LogDebug("crdtFile: {crdtFile}", crdtFile);
145145
logger.LogDebug("fwDataFile: {fwDataFile}", fwDataProject.FilePath);
146146

147-
var fwdataApi = await SetupFwData(fwDataProject, projectCode);
147+
FwDataMiniLcmApi? fwdataApi;
148+
try
149+
{
150+
fwdataApi = await SetupFwData(fwDataProject, projectCode);
151+
}
152+
catch (SendReceiveException e)
153+
{
154+
return new SyncJobResult(SyncJobStatusEnum.SendReceiveFailed, e.Message);
155+
}
148156
//always do this as existing projects need to run this even if they didn't S&R due to no pending changes
149157
await mediaFileService.SyncMediaFiles(fwdataApi.Cache);
150158

@@ -181,6 +189,10 @@ public async Task<SyncJobResult> ExecuteSync(CancellationToken stoppingToken)
181189
{
182190
var srResult2 = await srService.SendReceive(fwDataProject, projectCode);
183191
logger.LogInformation("Send/Receive result after CRDT sync: {srResult2}", srResult2.Output);
192+
if (srResult2.ErrorEncountered)
193+
{
194+
return new SyncJobResult(SyncJobStatusEnum.SendReceiveFailed, $"Send/Receive after CRDT sync failed: {srResult2.Output}");
195+
}
184196
}
185197
activity?.SetStatus(ActivityStatusCode.Ok, "Sync finished");
186198
return new SyncJobResult(result);
@@ -199,6 +211,10 @@ private async Task<FwDataMiniLcmApi> SetupFwData(FwDataProject fwDataProject, st
199211
{
200212
var srResult = await srService.SendReceive(fwDataProject, projectCode);
201213
logger.LogInformation("Send/Receive result before CRDT sync: {srResult}", srResult.Output);
214+
if (srResult.ErrorEncountered)
215+
{
216+
throw new SendReceiveException($"Send/Receive before CRDT sync failed: {srResult.Output}");
217+
}
202218
}
203219
}
204220
else

0 commit comments

Comments
 (0)