Skip to content

Commit

Permalink
Backend(,Tests): avoid inconsistency ex if no inconsistency
Browse files Browse the repository at this point in the history
This is the first part of a bugfix for issue 250 [1]. The exception
was misleading because it was not really an inconsistecy but rather
lacking availability.

[1] #250
  • Loading branch information
knocte committed Jan 24, 2024
1 parent 76067f7 commit 83a4d2e
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 11 deletions.
33 changes: 33 additions & 0 deletions src/GWallet.Backend.Tests/FaultTolerance.fs
Original file line number Diff line number Diff line change
Expand Up @@ -546,6 +546,39 @@ type FaultTolerance() =
|> ignore<int> )
Assert.That(inconsistencyEx.Message, IsString.WhichContains "received: 4, consistent: 2, required: 3")

[<Test>]
member __.``should not throw inconsistency exception if received results is less than required``() =
let numberOfConsistentResponsesToBeConsideredSafe = 2u
let consistencyConfig =
SpecificNumberOfConsistentResponsesRequired numberOfConsistentResponsesToBeConsideredSafe |> Some
let settings = defaultSettingsForNoConsistencyNoParallelismAndNoRetries consistencyConfig

let someResult = 1

let aJob1 =
async { return someResult }
let aJob2 =
async { return raise SomeSpecificException }
let aJob3 =
async { return raise SomeSpecificException }

let func1,func2,func3 = serverWithNoHistoryInfoBecauseIrrelevantToThisTest "aJob1" aJob1,
serverWithNoHistoryInfoBecauseIrrelevantToThisTest "aJob2" aJob2,
serverWithNoHistoryInfoBecauseIrrelevantToThisTest "aJob3" aJob3

let client = FaultTolerantParallelClient<ServerDetails, SomeSpecificException>
dummy_func_to_not_save_server_because_it_is_irrelevant_for_this_test

let notEngoughAvailableEx =
Assert.Throws<NotEnoughAvailableException>(fun _ ->
client.Query
settings
[ func1; func2; func3 ]
|> Async.RunSynchronously
|> ignore<int>
)
Assert.That(notEngoughAvailableEx.Message, IsString.WhichContains "received: 1, unavailable: 2, required: 2")

[<Test>]
member __.``using an average func instead of consistency``() =
let job1 =
Expand Down
50 changes: 39 additions & 11 deletions src/GWallet.Backend/FaultTolerantParallelClient.fs
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,40 @@ open Fsdk

open GWallet.Backend.FSharpUtil.UwpHacks

type ResourcesUnavailabilityException (message: string, innerOrLastException: Exception) =
inherit Exception (message, innerOrLastException)
type ResourcesUnavailabilityException =
inherit Exception

new(message: string, innerException: Exception) = { inherit Exception(message, innerException) }
new(message: string) = { inherit Exception(message) }

type private TaskUnavailabilityException (message: string, innerException: Exception) =
inherit ResourcesUnavailabilityException (message, innerException)

type private ServersUnavailabilityException (message: string, lastException: Exception) =
inherit ResourcesUnavailabilityException (message, lastException)
type ServersUnavailabilityException =
inherit ResourcesUnavailabilityException

new(message: string, innerException: Exception) = { inherit ResourcesUnavailabilityException(message, innerException) }
new(message: string) = { inherit ResourcesUnavailabilityException(message) }

type private NoneAvailableException (message:string, lastException: Exception) =
inherit ServersUnavailabilityException (message, lastException)

type private NotEnoughAvailableException (message:string, lastException: Exception) =
inherit ServersUnavailabilityException (message, lastException)
type NotEnoughAvailableException =
inherit ServersUnavailabilityException

new (message: string, innerException: Exception) =
{ inherit ServersUnavailabilityException (message, innerException) }
new (totalNumberOfSuccesfulResultsObtained: uint32,
numberOfServersUnavailable: uint32,
numberOfConsistentResultsRequired: uint32) =
{ inherit ServersUnavailabilityException ("Results obtained were not enough to be considered consistent" +
SPrintF3 " (received: %i, unavailable: %i, required: %i)"
totalNumberOfSuccesfulResultsObtained
numberOfServersUnavailable
numberOfConsistentResultsRequired)
}

type ResultInconsistencyException (totalNumberOfSuccesfulResultsObtained: int,
type ResultInconsistencyException (totalNumberOfSuccesfulResultsObtained: uint32,
maxNumberOfConsistentResultsObtained: int,
numberOfConsistentResultsRequired: uint32) =
inherit Exception ("Results obtained were not enough to be considered consistent" +
Expand Down Expand Up @@ -591,7 +609,8 @@ type FaultTolerantParallelClient<'K,'E when 'K: equality and 'K :> ICommunicatio
retriesForInconsistency
cancellationSource
else
let totalNumberOfSuccesfulResultsObtained = executedServers.SuccessfulResults.Length
let totalNumberOfSuccesfulResultsObtained = uint executedServers.SuccessfulResults.Length
let totalNumberOfUnavailableServers = uint failedFuncs.Length

// HACK: we do this as a quick fix wrt new OneServerConsistentWithCertainValueOrTwoServers setting, but we should
// (TODO) rather throw a specific overload of ResultInconsistencyException about this mode being used
Expand All @@ -609,9 +628,18 @@ type FaultTolerantParallelClient<'K,'E when 'K: equality and 'K :> ICommunicatio
return failwith "resultsSoFar.Length != 0 but MeasureConsistency returns None, please report this bug"
| (_,maxNumberOfConsistentResultsObtained)::_ ->
if (retriesForInconsistency = settings.NumberOfRetriesForInconsistency) then
return raise (ResultInconsistencyException(totalNumberOfSuccesfulResultsObtained,
maxNumberOfConsistentResultsObtained,
numberOfConsistentResponsesRequired))
if totalNumberOfSuccesfulResultsObtained >= numberOfConsistentResponsesRequired then
return raise (ResultInconsistencyException(totalNumberOfSuccesfulResultsObtained,
maxNumberOfConsistentResultsObtained,
numberOfConsistentResponsesRequired))
else
return
raise
<| NotEnoughAvailableException(
totalNumberOfSuccesfulResultsObtained,
totalNumberOfUnavailableServers,
numberOfConsistentResponsesRequired
)
else
return! QueryInternalImplementation
settings
Expand Down

0 comments on commit 83a4d2e

Please sign in to comment.