public void ValidateDurableAbortReconnection() { IOperationDispatcher serverDispatcher = new OperationDispatcher(); StatelessServerEndpoint server = new StatelessServerEndpoint(url, serverDispatcher); serverDispatcher.RegisterHandler <IWeakCalculator>(new WeakCalculator { Destroyed = () => server.Dispose() }); server.Start(); using (DurableClientConnection client = new DurableClientConnection(url)) { client.ConnectionPaused = response => response.Abort = true; client.Open(); IWeakCalculator calculator = client.RemoteExecutor.Create <IWeakCalculator>(); Assert.AreEqual(4, calculator.Add(2, 2)); calculator.Destroy(); server = new StatelessServerEndpoint(url2, serverDispatcher); server.Start(); bool exceptionThrown = false; try { calculator.Add(5, 6); } catch (NotConnectedException ex) { exceptionThrown = ex.Message == "Network connection is not opened."; } Assert.IsTrue(exceptionThrown); server.Dispose(); } }
/// <summary> /// Creates a client connection for the specified fabric address (beginning with fabric:/) /// </summary> /// <param name="fabricAddress"></param> /// <param name="resolver">Non-default ServicePartitionResolver</param> /// todo: make sure custom partitioning works (and in the process learn how custom partitioning works) public FabricClientConnection(Uri fabricAddress, ServicePartitionResolver resolver) { FabricAddress = fabricAddress; Resolver = resolver; selectedEndpoint = ResolveAnyEndpoint().Result; clientConnection = new DurableClientConnection(selectedEndpoint.Address) { ConnectionPaused = OnConnectionPaused }; clientConnection.Closed += () => Closed?.Invoke(); }
static void Main(string[] args) { DurableConfigurator.Configure(); // Note that using the type DurableClientConnection here is not absolutely necessary. // Because the transport layer provider will always provide DurableLidgrenClientChannels, the channels themselves will be durable, // but accessing the Durable events is a pain. using (var client = new DurableClientConnection("net://localhost:3133/DurableServices")) { bool stop = false; bool wait = false; client.ConnectionPaused = response => Console.WriteLine("\tConnection lost; attempting to reconnect..."); client.ConnectionRestored += () => Console.WriteLine("\tConnection has been restored."); client.ConnectionAborted += () => { Console.WriteLine("\tConnection has been aborted."); wait = true; stop = true; }; client.Closed += () => Console.WriteLine("\tConnection has been closed."); client.Open(); ICalculator calculator = client.RemoteExecutor.Create <ICalculator>(); Console.WriteLine("Sending periodic requests. Press enter to exit."); Task.Run(() => { Console.ReadLine(); stop = true; }); while (!stop) { int sleep = R() % 1000 + 300; Task.Run(() => AsyncAdd(R() % 100, R() % 100, calculator)); Thread.Sleep(sleep); } if (wait) { Console.WriteLine("\tPress enter to exit."); Console.ReadLine(); } } }
public void ValidateDurableFailoverToNewEndPoint() { IOperationDispatcher serverDispatcher = new OperationDispatcher(); StatelessServerEndpoint server = new StatelessServerEndpoint(url, serverDispatcher); serverDispatcher.RegisterHandler <IWeakCalculator>(new WeakCalculator { Destroyed = () => server.Dispose() }); server.Start(); using (DurableClientConnection client = new DurableClientConnection(url)) { client.ConnectionPaused = response => response.ReconnectPort = Port2; client.Open(); IWeakCalculator calculator = client.RemoteExecutor.Create <IWeakCalculator>(); Assert.AreEqual(4, calculator.Add(2, 2)); calculator.Destroy(); server = new StatelessServerEndpoint(url2, serverDispatcher); server.Start(); Assert.AreEqual(11, calculator.Add(5, 6)); server.Dispose(); } }
static void Main(string[] args) { // todo: durable DurableConfigurator.Configure(); // note that at most one process can use a single UDP port on a machine. // Because of this, the service fabric services exposed to the client via this port cannot be replicated // on local.1node // If you deploy to an actual service fabric cluster, then the service can be replicated on several machines // and reached via the load balancer. This means that if a service has a high spin up cost, your reconnection // time is just a combination of the timeout and the load balancer's health ping. // Note that you will want to have the load balancer hash on client IP (hashing on client port is not required) // // However, the ServiceFabric.Stateless executable is only reachable via the naming service, so it doesn't // require a dedicated port. This means that when using local.5node, there will be 5 stateless executables. // Thus replacing this internal client is virtually free, since it just takes talking to the naming service. using (var strongCalculator = new DurableClientConnection("net://localhost:3232/StrongCalculatorApplicationId")) using (var weakCounter = new DurableClientConnection("net://localhost:3233/WeakCounterApplicationId")) { //strongCalculator.Open(); weakCounter.Open(); strongCalculator.ConnectionAborted += () => Console.WriteLine("\tStrong calculator connection aborted."); strongCalculator.ConnectionInterrupted += () => Console.WriteLine("\tStrong calculator connection interrupted."); strongCalculator.ConnectionRestored += () => Console.WriteLine("\tStrong calculator connection restored."); weakCounter.ConnectionAborted += () => Console.WriteLine("\tWeak counter connection aborted."); weakCounter.ConnectionInterrupted += () => Console.WriteLine("\tWeak counter connection interrupted."); weakCounter.ConnectionRestored += () => Console.WriteLine("\tWeak counter connection restored."); //var calculator = strongCalculator.RemoteExecutor.Create<IWeakCalculator>(); var counter = weakCounter.RemoteExecutor.Create <IWeakCounter>(); Console.WriteLine("Connected to StrongCalculator and WeakCounter."); //Console.WriteLine("4 + 5 = " + calculator.Add(4, 5)); //Console.WriteLine("Crashing calculator"); //calculator.Crash(); //Console.WriteLine("9 + 5 = " + calculator.Add(9, 5)); Console.WriteLine("Incrementing..."); counter.Increment(); Console.WriteLine("Incrementing..."); counter.Increment(); Console.WriteLine("Incrementing..."); counter.Increment(); Console.WriteLine("Incrementing..."); counter.Increment(); Console.WriteLine("Count: " + counter.GetCount()); Console.WriteLine("Crashing counter..."); counter.Crash(); // Wait a short while to ensure crash Console.WriteLine("Sleeping to ensure service crashes before next call"); Thread.Sleep(1500); //Console.WriteLine("3 + 2 = " + calculator.Add(3, 2)); Console.WriteLine("Incrementing..."); try { counter.Increment(); Console.WriteLine("Count: " + counter.GetCount()); } catch (ConnectionOpenException) { Console.WriteLine("Connection was not re-established soon enough."); Console.WriteLine("Consider increasing timeout, retry attempts, or "); Console.WriteLine("decreasing time until the service comes back online."); Console.WriteLine("Done. Press enter to exit."); Console.ReadLine(); return; } Console.WriteLine("Count was not persisted because example service does not use persistence."); Console.WriteLine("Should persistence be applied (ReliableCollections) or otherwise,"); Console.WriteLine("then the client would not see any issues."); Console.WriteLine("Done. Press enter to exit."); Console.ReadLine(); } }