public async Task TimeoutsAfterMultipleRetries() { var address = NetworkAddress.Parse("127.0.0.1:11001"); using var _ = HConsole.Capture(consoleOptions => consoleOptions .ClearAll() .Configure().SetMaxLevel() .Configure(this).SetPrefix("TEST") .Configure <AsyncContext>().SetMinLevel() .Configure <SocketConnectionBase>().SetIndent(1).SetLevel(0).SetPrefix("SOCKET")); HConsole.WriteLine(this, "Begin"); HConsole.WriteLine(this, "Start server"); await using var server = new Server(address, async(xsvr, xconn, xmsg) => await HandleAsync(xsvr, xconn, xmsg, async(svr, conn, msg) => { HConsole.WriteLine(svr, "Handle request (wait...)"); await Task.Delay(500).CfAwait(); HConsole.WriteLine(svr, "Respond with error."); var response = ErrorsServerCodec.EncodeResponse(new[] { // make sure the error is retryable new ErrorHolder(RemoteError.RetryableHazelcast, "classname", "message", Enumerable.Empty <StackTraceElement>()) }); //HConsole.WriteLine(svr, "Respond with success."); //var response = ClientPingServerCodec.EncodeResponse(); response.CorrelationId = msg.CorrelationId; await conn.SendAsync(response).CfAwait(); }), LoggerFactory); await server.StartAsync().CfAwait(); HConsole.WriteLine(this, "Start client"); var options = HazelcastOptions.Build(configure: (configuration, options) => { options.Networking.Addresses.Add("127.0.0.1:11001"); options.Messaging.RetryTimeoutSeconds = 3; // default value is 120s }); await using var client = (HazelcastClient) await HazelcastClientFactory.StartNewClientAsync(options); HConsole.WriteLine(this, "Send message"); var message = ClientPingServerCodec.EncodeRequest(); // note: the error only happens *after* the server has responded // we could wait for the response for ever await AssertEx.ThrowsAsync <TaskTimeoutException>(async() => { // server will respond w/ error every 500ms and client will retry // until the 3s retry timeout (options above) is reached await client.Cluster.Messaging.SendAsync(message).CfAwait(); }); await server.StopAsync().CfAwait(); }
private ClientMessage CreateErrorMessage(RemoteError error) { // can we prepare server messages? var errorHolders = new List <ErrorHolder> { new ErrorHolder(error, "className", "message", Enumerable.Empty <StackTraceElement>()) }; return(ErrorsServerCodec.EncodeResponse(errorHolders)); }
private async ValueTask ServerHandler(Server s, ClientMessageConnection conn, ClientMessage msg) { async Task SendResponseAsync(ClientMessage response) { response.CorrelationId = msg.CorrelationId; response.Flags |= ClientMessageFlags.BeginFragment | ClientMessageFlags.EndFragment; await conn.SendAsync(response).CfAwait(); } async Task SendEventAsync(ClientMessage eventMessage, long correlationId) { eventMessage.CorrelationId = correlationId; eventMessage.Flags |= ClientMessageFlags.BeginFragment | ClientMessageFlags.EndFragment; await conn.SendAsync(eventMessage).CfAwait(); } async Task SendErrorAsync(RemoteError error, string message) { var errorHolders = new List <ErrorHolder> { new ErrorHolder(error, "?", message, Enumerable.Empty <StackTraceElement>()) }; var response = ErrorsServerCodec.EncodeResponse(errorHolders); await SendResponseAsync(response).CfAwait(); } var state = (ServerState)s.State; var address = s.Address; const int partitionsCount = 2; switch (msg.MessageType) { // must handle auth case ClientAuthenticationServerCodec.RequestMessageType: { HConsole.WriteLine(this, $"(server{state.Id}) Authentication"); var authRequest = ClientAuthenticationServerCodec.DecodeRequest(msg); var authResponse = ClientAuthenticationServerCodec.EncodeResponse( 0, address, s.MemberId, SerializationService.SerializerVersion, "4.0", partitionsCount, s.ClusterId, false); await SendResponseAsync(authResponse).CfAwait(); break; } // must handle events case ClientAddClusterViewListenerServerCodec.RequestMessageType: { HConsole.WriteLine(this, $"(server{state.Id}) AddClusterViewListener"); var addRequest = ClientAddClusterViewListenerServerCodec.DecodeRequest(msg); var addResponse = ClientAddClusterViewListenerServerCodec.EncodeResponse(); await SendResponseAsync(addResponse).CfAwait(); _ = Task.Run(async() => { await Task.Delay(500).CfAwait(); const int membersVersion = 1; var memberVersion = new MemberVersion(4, 0, 0); var memberAttributes = new Dictionary <string, string>(); var membersEventMessage = ClientAddClusterViewListenerServerCodec.EncodeMembersViewEvent(membersVersion, new[] { new MemberInfo(state.MemberIds[0], state.Addresses[0], memberVersion, false, memberAttributes), new MemberInfo(state.MemberIds[1], state.Addresses[1], memberVersion, false, memberAttributes), }); await SendEventAsync(membersEventMessage, msg.CorrelationId).CfAwait(); await Task.Delay(500).CfAwait(); const int partitionsVersion = 1; var partitionsEventMessage = ClientAddClusterViewListenerServerCodec.EncodePartitionsViewEvent(partitionsVersion, new[] { new KeyValuePair <Guid, IList <int> >(state.MemberIds[0], new List <int> { 0 }), new KeyValuePair <Guid, IList <int> >(state.MemberIds[1], new List <int> { 1 }), }); await SendEventAsync(partitionsEventMessage, msg.CorrelationId).CfAwait(); }); break; } // create object case ClientCreateProxyServerCodec.RequestMessageType: { HConsole.WriteLine(this, $"(server{state.Id}) CreateProxy"); var createRequest = ClientCreateProxyServerCodec.DecodeRequest(msg); var createResponse = ClientCreateProxiesServerCodec.EncodeResponse(); await SendResponseAsync(createResponse).CfAwait(); break; } // subscribe case MapAddEntryListenerServerCodec.RequestMessageType: { HConsole.WriteLine(this, $"(server{state.Id}) AddEntryListener"); var addRequest = MapAddEntryListenerServerCodec.DecodeRequest(msg); state.Subscribed = true; state.SubscriptionCorrelationId = msg.CorrelationId; var addResponse = MapAddEntryListenerServerCodec.EncodeResponse(state.SubscriptionId); await SendResponseAsync(addResponse).CfAwait(); break; } // unsubscribe // server 1 removes on first try, server 2 removes on later tries case MapRemoveEntryListenerServerCodec.RequestMessageType: { HConsole.WriteLine(this, $"(server{state.Id}) RemoveEntryListener"); var removeRequest = MapRemoveEntryListenerServerCodec.DecodeRequest(msg); var removed = state.Subscribed && removeRequest.RegistrationId == state.SubscriptionId; removed &= state.Id == 0 || state.UnsubscribeCount++ > 0; if (removed) { state.Subscribed = false; } HConsole.WriteLine(this, $"(server{state.Id}) Subscribed={state.Subscribed}"); var removeResponse = MapRemoveEntryListenerServerCodec.EncodeResponse(removed); await SendResponseAsync(removeResponse).CfAwait(); break; } // add to map & trigger event case MapSetServerCodec.RequestMessageType: { HConsole.WriteLine(this, $"(server{state.Id}) Set"); var setRequest = MapSetServerCodec.DecodeRequest(msg); var setResponse = MapSetServerCodec.EncodeResponse(); await SendResponseAsync(setResponse).CfAwait(); HConsole.WriteLine(this, $"(server{state.Id}) Subscribed={state.Subscribed}"); if (state.Subscribed) { HConsole.WriteLine(this, $"(server{state.Id}) Trigger event"); var key = setRequest.Key; var value = setRequest.Value; var addedEvent = MapAddEntryListenerServerCodec.EncodeEntryEvent(key, value, value, value, (int)MapEventTypes.Added, state.SubscriptionId, 1); await SendEventAsync(addedEvent, state.SubscriptionCorrelationId).CfAwait(); } break; } // unexpected message = error default: { // RemoteError.Hazelcast or RemoteError.RetryableHazelcast var messageName = MessageTypeConstants.GetMessageTypeName(msg.MessageType); await SendErrorAsync(RemoteError.Hazelcast, $"MessageType {messageName} (0x{msg.MessageType:X}) not implemented.").CfAwait(); break; } } }