public void TestBindable() { ClientWire.AutoTransmitMode = true; ServerWire.AutoTransmitMode = true; var call1 = new RdCall <Unit, RdSignal <int> >(Serializers.ReadVoid, Serializers.WriteVoid, RdSignal <int> .Read, RdSignal <int> .Write); var call2 = new RdCall <Unit, RdSignal <int> >(Serializers.ReadVoid, Serializers.WriteVoid, RdSignal <int> .Read, RdSignal <int> .Write); var respSignal = new RdSignal <int>(); var endpointLfTerminated = false; call2.Set((endpointLf, _) => { endpointLf.OnTermination(() => endpointLfTerminated = true); return(RdTask <RdSignal <int> > .Successful(respSignal)); }); var serverEntity = BindToServer(LifetimeDefinition.Lifetime, call1, ourKey); var clientEntity = BindToClient(LifetimeDefinition.Lifetime, call2, ourKey); var ld = new LifetimeDefinition(); var lf = ld.Lifetime; var signal = call1.Start(lf, Unit.Instance).AsTask().GetOrWait(lf); var log = new List <int>(); signal.Advise(Lifetime.Eternal, v => { log.Add(v); Console.WriteLine(v); }); respSignal.Fire(1); respSignal.Fire(2); respSignal.Fire(3); ld.Terminate(); Assert.False(respSignal.IsBound); SpinWaitEx.SpinUntil(() => log.Count >= 3); Thread.Sleep(100); Assert.AreEqual(new [] { 1, 2, 3 }, log.ToArray()); Assert.True(endpointLfTerminated); }
/// <summary> /// Sync call which allow nested call execution with help of <see cref="SwitchingScheduler"/> /// </summary> public static TRes SyncNested <TReq, TRes>(RdCall <TReq, TRes> call, Lifetime lifetime, TReq request, RpcTimeouts timeouts = null) { Assertion.Require(call.IsBound, "Not bound: {0}", call); // Sync calls can called only under the protocol's scheduler. // If you want to mitigate this limitation, keep in mind that if you make a sync call from background thread // with some small probability your call can be merged in the sync execution of other call. Usually it is not // desired behaviour as you can accidentally obtain undesired locks. call.Proto.Scheduler.AssertThread(); var nestedCallsScheduler = new LifetimeDefinition(); var responseScheduler = new RdSimpleDispatcher(nestedCallsScheduler.Lifetime, Log.GetLog(call.GetType())); using (new SwitchingScheduler.SwitchCookie(responseScheduler)) { var task = call.Start(lifetime, request, responseScheduler); task.Result.Advise(nestedCallsScheduler.Lifetime, result => { nestedCallsScheduler.Terminate(); }); RpcTimeouts timeoutsToUse = RpcTimeouts.GetRpcTimeouts(timeouts); responseScheduler.MessageTimeout = timeoutsToUse.ErrorAwaitTime; var stopwatch = Stopwatch.StartNew(); responseScheduler.Run(); if (!task.Result.HasValue()) { throw new TimeoutException($"Sync execution of rpc `{call.Location}` is timed out in {timeoutsToUse.ErrorAwaitTime.TotalMilliseconds} ms"); } stopwatch.Stop(); var freezeTime = stopwatch.ElapsedMilliseconds; if (freezeTime > timeoutsToUse.WarnAwaitTime.TotalMilliseconds) { Log.Root.Error("Sync execution of rpc `{0}` executed too long: {1} ms", call.Location, freezeTime); } return(task.Result.Value.Unwrap()); } }