/// <summary> /// Handles a connection to a new cluster. /// </summary> #pragma warning disable IDE0060 // Remove unused parameters #pragma warning disable CA1801 // Review unused parameters // unused parameters are required, this is an event handler public ValueTask OnConnectionOpened(MemberConnection connection, bool isFirstEver, bool isFirst, bool isNewCluster) #pragma warning restore CA1801 #pragma warning restore IDE0060 { if (!isNewCluster) { return(default);
/// <summary> /// Handles a closed connection. /// </summary> /// <param name="connection">The connection.</param> /// <param name="wasLast">Whether the connection was the last one.</param> public ValueTask OnConnectionClosed(MemberConnection connection, bool wasLast) { var args = new ConnectionClosedEventArgs(wasLast); // trigger ConnectionRemoved event return(ForEachHandler <ConnectionClosedEventHandler, ConnectionClosedEventArgs>( (handler, sender, a) => handler.HandleAsync(sender, a), args)); }
/// <summary> /// Begins the transaction. /// </summary> public async Task BeginAsync() { if (State != TransactionState.None) { throw new InvalidOperationException("The transaction context is already involved in a transaction."); } var asyncContext = AsyncContext.Current; lock (_inTransactionMutex) { // this is used to prevent an asynchronous context from being in multiple (thus nested) transactions, // it was implemented, before async, via a [ThreadStatic] boolean (when everything was bound to // threads) which cannot be appropriate anymore. instead we move it to the async context. if (asyncContext.InTransaction) { throw new InvalidOperationException("Nested transactions are not supported."); } asyncContext.InTransaction = true; } _connection = _cluster.Members.GetRandomConnection(); if (_connection == null) { throw _cluster.State.ThrowClientOfflineException(); } _threadId = ContextId; //_startTime = Clock.Milliseconds; HConsole.WriteLine(this, $"Begin transaction on context #{ContextId}"); try { // codec wants 0 for server config, -1 for infinite (?) var timeoutMs = _options.Timeout.RoundedMilliseconds(false); var requestMessage = TransactionCreateCodec.EncodeRequest(timeoutMs, _options.Durability, (int)_options.Type, ContextId); var responseMessage = await _cluster.Messaging.SendToMemberAsync(requestMessage, _connection).CfAwait(); TransactionId = TransactionCreateCodec.DecodeResponse(responseMessage).Response; State = TransactionState.Active; } catch { lock (_inTransactionMutex) asyncContext.InTransaction = false; _threadId = 0; //_startTime = 0; TransactionId = default; State = TransactionState.None; throw; } }
public async Task Auth() { // need to start a real server (not the RC thing!) //var address = NetworkAddress.Parse("sgay-l4"); var address = NetworkAddress.Parse("localhost"); HConsole.Configure(this, config => config.SetIndent(0).SetPrefix("TEST")); HConsole.WriteLine(this, "Begin"); HConsole.WriteLine(this, "Start client "); var client1 = new MemberConnection(address, new MessagingOptions(), new SocketOptions(), new SslOptions(), new Int64Sequence(), new NullLoggerFactory()); await client1.ConnectAsync(CancellationToken.None).CAF(); // RC assigns a GUID but the default cluster name is 'dev' var clusterName = "dev"; var username = (string)null; // null var password = (string)null; // null var clientId = Guid.NewGuid(); var clientType = "CSP"; // CSharp var serializationVersion = (byte)0x01; var clientVersion = "4.0"; var clientName = "hz.client_0"; var labels = new HashSet <string>(); var requestMessage = ClientAuthenticationCodec.EncodeRequest(clusterName, username, password, clientId, clientType, serializationVersion, clientVersion, clientName, labels); HConsole.WriteLine(this, "Send auth request"); var invocation = new Invocation(requestMessage, new MessagingOptions(), null, CancellationToken.None); var responseMessage = await client1.SendAsync(invocation, CancellationToken.None).CAF(); HConsole.WriteLine(this, "Rcvd auth response " + HConsole.Lines(this, 1, responseMessage.Dump())); var response = ClientAuthenticationCodec.DecodeResponse(responseMessage); var status = (AuthenticationStatus)response.Status; NUnit.Framework.Assert.AreEqual(AuthenticationStatus.Authenticated, status); HConsole.WriteLine(this, "Stop client"); await client1.DisposeAsync().CAF(); HConsole.WriteLine(this, "End"); await Task.Delay(100).CAF(); }
/// <summary> /// Handles an opened connection. /// </summary> /// <param name="connection">The connection.</param> /// <param name="isFirst">Whether the connection is the first one.</param> /// <param name="isNewCluster">Whether the cluster is a new/different cluster.</param> public async ValueTask OnConnectionOpened(MemberConnection connection, bool isFirst, bool isNewCluster) { // if it is the first connection, subscribe to events according to options if (isFirst) { // FIXME should this be cancelable? var cancellationToken = CancellationToken.None; foreach (var subscriber in _options.Subscribers) { await subscriber.SubscribeAsync(this, cancellationToken).CfAwait(); } } var args = new ConnectionOpenedEventArgs(isFirst); // trigger ConnectionOpened event await ForEachHandler <ConnectionOpenedEventHandler, ConnectionOpenedEventArgs>( (handler, sender, a) => handler.HandleAsync(sender, a), args).CfAwait(); }
public async Task Test() { using var _ = HConsoleForTest(); var options = HazelcastOptions.Build(); options.Messaging.RetryTimeoutSeconds = 1; var loggerFactory = new NullLoggerFactory(); var address = NetworkAddress.Parse("127.0.0.1:11000"); var state = new ServerState { Id = 0, MemberId = Guid.NewGuid(), Address = address }; await using var server = new Server(address, ServerHandler, loggerFactory, state, "0") { MemberId = state.MemberId, }; await server.StartAsync(); var serializationService = HazelcastClientFactory.CreateSerializationService(options.Serialization, loggerFactory); var authenticator = new Authenticator(options.Authentication, serializationService); ISequence <int> connectionIdSequence = new Int32Sequence(); ISequence <long> correlationIdSequence = new Int64Sequence(); var memberConnection = new MemberConnection(address, authenticator, options.Messaging, options.Networking, options.Networking.Ssl, connectionIdSequence, correlationIdSequence, loggerFactory); var memberConnectionHasClosed = false; memberConnection.Closed += connection => { memberConnectionHasClosed = true; return(default);
/// <summary> /// Creates all known <see cref="IDistributedObject"/> on a cluster. /// </summary> /// <returns>A task that will complete when the state has been sent.</returns> /// <remarks> /// <para>This is used when connecting to a new cluster.</para> /// </remarks> public async ValueTask CreateAllAsync(MemberConnection connection) { await foreach (var(key, _) in _objects) { // if the connection goes down, stop if (!connection.Active) { return; } try { var requestMessage = ClientCreateProxyCodec.EncodeRequest(key.Name, key.ServiceName); await _cluster.Messaging.SendToMemberAsync(requestMessage, connection).CfAwait(); } catch (Exception e) { _logger.LogError(e, $"Failed to create ({key}) distributed object on new cluster."); } } }
public HTxDictionary(string name, DistributedObjectFactory factory, Cluster cluster, MemberConnection transactionClientConnection, Guid transactionId, ISerializationService serializationService, ILoggerFactory loggerFactory) : base(HDictionary.ServiceName, name, factory, cluster, transactionClientConnection, transactionId, serializationService, loggerFactory) { }
/// <summary> /// Handles a connection to a new cluster. /// </summary> public ValueTask OnConnectionOpened(MemberConnection connection, bool isFirst, bool isNewCluster) { if (!isNewCluster) { return(default);
/// <summary> /// Initializes a new instance of the <see cref="ConnectionClosedEventArgs"/> class. /// </summary> /// <param name="connection">The connection that was closed.</param> public ConnectionClosedEventArgs(MemberConnection connection) { Connection = connection; }
/// <summary> /// Initializes a new instance of the <see cref="TransactionalDistributedObjectBase"/> class. /// </summary> /// <param name="serviceName">the name of the service managing this object.</param> /// <param name="name">The unique name of the object.</param> /// <param name="factory">The factory that owns this object.</param> /// <param name="cluster">A cluster.</param> /// <param name="transactionClientConnection">The client connection supporting the transaction.</param> /// <param name="transactionId">The unique identifier of the transaction.</param> /// <param name="serializationService">A serialization service.</param> /// <param name="loggerFactory">A logger factory.</param> protected TransactionalDistributedObjectBase(string serviceName, string name, DistributedObjectFactory factory, Cluster cluster, MemberConnection transactionClientConnection, Guid transactionId, SerializationService serializationService, ILoggerFactory loggerFactory) : base(serviceName, name, factory, cluster, serializationService, loggerFactory) { TransactionId = transactionId; TransactionClientConnection = transactionClientConnection; }
public HTxMultiMap(string name, DistributedObjectFactory factory, Cluster cluster, MemberConnection transactionClientConnection, Guid transactionId, SerializationService serializationService, ILoggerFactory loggerFactory) : base(ServiceNames.MultiMap, name, factory, cluster, transactionClientConnection, transactionId, serializationService, loggerFactory) { }
/// <summary> /// Initializes a new instance of the <see cref="ConnectionOpenedEventArgs"/> class. /// </summary> /// <param name="connection">The connection that was opened.</param> /// <param name="isNewCluster">Whether the connection is the first connection to a new cluster.</param> public ConnectionOpenedEventArgs(MemberConnection connection, bool isNewCluster) { Connection = connection; IsNewCluster = isNewCluster; }