Ejemplo n.º 1
0
        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);
        }
Ejemplo n.º 2
0
        /// <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());
            }
        }