private static IRequest JoinGroupRequest(IRequestContext context, ArraySegment <byte> payload) { using (var reader = ReadHeader(payload)) { var groupId = reader.ReadString(); var sessionTimeout = TimeSpan.FromMilliseconds(reader.ReadInt32()); TimeSpan?rebalanceTimeout = null; if (context.ApiVersion >= 1) { rebalanceTimeout = TimeSpan.FromMilliseconds(reader.ReadInt32()); } var memberId = reader.ReadString(); var protocolType = reader.ReadString(); var groupProtocols = new JoinGroupRequest.GroupProtocol[reader.ReadInt32()]; var encoder = context.GetEncoder(protocolType); for (var g = 0; g < groupProtocols.Length; g++) { var protocolName = reader.ReadString(); var metadata = encoder.DecodeMetadata(protocolName, reader); groupProtocols[g] = new JoinGroupRequest.GroupProtocol(metadata); } return(new JoinGroupRequest(groupId, sessionTimeout, memberId, protocolType, groupProtocols, rebalanceTimeout)); } }
public async Task ConsumerSyncsGroupAfterJoining() { var protocol = new JoinGroupRequest.GroupProtocol(new ConsumerProtocolMetadata("mine")); var router = Substitute.For <IRouter>(); var conn = Substitute.For <IConnection>(); router.GetGroupConnectionAsync(Arg.Any <string>(), Arg.Any <CancellationToken>()) .Returns(_ => Task.FromResult(new GroupConnection(_.Arg <string>(), 0, conn))); router.SyncGroupAsync(Arg.Any <SyncGroupRequest>(), Arg.Any <IRequestContext>(), Arg.Any <IRetry>(), Arg.Any <CancellationToken>()) .Returns(_ => Task.FromResult(new SyncGroupResponse(ErrorCode.NONE, new ConsumerMemberAssignment(new [] { new TopicPartition("name", 0) })))); var request = new JoinGroupRequest(TestConfig.GroupId(), TimeSpan.FromSeconds(30), "", ConsumerEncoder.Protocol, new [] { protocol }); var memberId = Guid.NewGuid().ToString("N"); var response = new JoinGroupResponse(ErrorCode.NONE, 1, protocol.protocol_name, memberId, memberId, new [] { new JoinGroupResponse.Member(memberId, new ConsumerProtocolMetadata("mine")) }); using (new GroupConsumer(router, request.group_id, request.protocol_type, response)) { await Task.Delay(300); } #pragma warning disable 4014 router.Received().SyncGroupAsync( Arg.Is((SyncGroupRequest s) => s.group_id == request.group_id && s.member_id == memberId), Arg.Any <IRequestContext>(), Arg.Any <IRetry>(), Arg.Any <CancellationToken>()); conn.DidNotReceive().SendAsync( Arg.Is((HeartbeatRequest s) => s.group_id == request.group_id && s.member_id == memberId), Arg.Any <CancellationToken>(), Arg.Any <IRequestContext>()); #pragma warning restore 4014 }
public async Task ConsumerHeartbeatsWithinTimeLimit(int heartbeatMilliseconds, int totalMilliseconds) { var protocol = new JoinGroupRequest.GroupProtocol(new ConsumerProtocolMetadata("mine")); var router = Substitute.For <IRouter>(); var conn = Substitute.For <IConnection>(); router.GetGroupConnectionAsync(Arg.Any <string>(), Arg.Any <CancellationToken>()) .Returns(_ => Task.FromResult(new GroupConnection(_.Arg <string>(), 0, conn))); var lastHeartbeat = DateTimeOffset.UtcNow; var heartbeatIntervals = ImmutableArray <TimeSpan> .Empty; conn.SendAsync(Arg.Any <HeartbeatRequest>(), Arg.Any <CancellationToken>(), Arg.Any <IRequestContext>()) .Returns(_ => { heartbeatIntervals = heartbeatIntervals.Add(DateTimeOffset.UtcNow - lastHeartbeat); lastHeartbeat = DateTimeOffset.UtcNow; return(Task.FromResult(new HeartbeatResponse(ErrorCode.NONE))); }); var request = new JoinGroupRequest(TestConfig.GroupId(), TimeSpan.FromMilliseconds(heartbeatMilliseconds), "", ConsumerEncoder.Protocol, new [] { protocol }); var memberId = Guid.NewGuid().ToString("N"); var response = new JoinGroupResponse(ErrorCode.NONE, 1, protocol.protocol_name, memberId, memberId, new [] { new JoinGroupResponse.Member(memberId, new ConsumerProtocolMetadata("mine")) }); lastHeartbeat = DateTimeOffset.UtcNow; using (new GroupConsumer(router, request.group_id, request.protocol_type, response)) { await Task.Delay(totalMilliseconds); } foreach (var interval in heartbeatIntervals) { Assert.That((int)interval.TotalMilliseconds, Is.AtMost(heartbeatMilliseconds)); } }
public async Task ConsumerHeartbeatsUntilDisposed(int heartbeatMilliseconds) { var protocol = new JoinGroupRequest.GroupProtocol(new ConsumerProtocolMetadata("mine")); var router = Substitute.For <IRouter>(); var conn = Substitute.For <IConnection>(); router.GetConnectionAsync(Arg.Any <string>(), Arg.Any <string>(), Arg.Any <CancellationToken>()) .Returns(_ => Task.FromResult(conn)); router.SyncGroupAsync(Arg.Any <SyncGroupRequest>(), Arg.Any <IRequestContext>(), Arg.Any <IRetry>(), Arg.Any <CancellationToken>()) .Returns(_ => Task.FromResult(new SyncGroupResponse(ErrorCode.NONE, new ConsumerMemberAssignment(new [] { new TopicPartition("name", 0) })))); conn.SendAsync(Arg.Any <HeartbeatRequest>(), Arg.Any <CancellationToken>(), Arg.Any <IRequestContext>()) .Returns(_ => Task.FromResult(new HeartbeatResponse(ErrorCode.NETWORK_EXCEPTION))); var heartbeat = TimeSpan.FromMilliseconds(heartbeatMilliseconds); var config = new ConsumerConfiguration(heartbeatTimeout: heartbeat, coordinationRetry: Retry.Until(heartbeat, maximumDelay: TimeSpan.FromMilliseconds(50))); var request = new JoinGroupRequest(TestConfig.GroupId(), config.GroupHeartbeat, "", ConsumerEncoder.Protocol, new [] { protocol }); var memberId = Guid.NewGuid().ToString("N"); var response = new JoinGroupResponse(ErrorCode.NONE, 1, protocol.protocol_name, memberId, memberId, new [] { new JoinGroupResponse.Member(memberId, new ConsumerProtocolMetadata("mine")) }); using (new GroupConsumer(router, request.group_id, request.protocol_type, response, config)) { await Task.Delay(heartbeatMilliseconds * 3); #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed conn.DidNotReceive().SendAsync( Arg.Is((LeaveGroupRequest s) => s.group_id == request.group_id && s.member_id == memberId), Arg.Any <CancellationToken>(), Arg.Any <IRequestContext>()); } conn.Received().SendAsync( Arg.Is((LeaveGroupRequest s) => s.group_id == request.group_id && s.member_id == memberId), Arg.Any <CancellationToken>(), Arg.Any <IRequestContext>()); #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed Assert.That(conn.ReceivedCalls().Count(c => c.GetMethodInfo().Name == nameof(Connection.SendAsync) && (c.GetArguments()[0] as HeartbeatRequest) != null), Is.AtLeast(2)); }
public async Task ConsumerHeartbeatsAtDesiredIntervals(int expectedHeartbeats, int heartbeatMilliseconds, int totalMilliseconds) { var protocol = new JoinGroupRequest.GroupProtocol(new ConsumerProtocolMetadata("mine")); var router = Substitute.For <IRouter>(); var conn = Substitute.For <IConnection>(); router.GetConnectionAsync(Arg.Any <string>(), Arg.Any <string>(), Arg.Any <CancellationToken>()) .Returns(_ => Task.FromResult(conn)); router.SyncGroupAsync(Arg.Any <SyncGroupRequest>(), Arg.Any <IRequestContext>(), Arg.Any <IRetry>(), Arg.Any <CancellationToken>()) .Returns(_ => Task.FromResult(new SyncGroupResponse(ErrorCode.NONE, new ConsumerMemberAssignment(new [] { new TopicPartition("name", 0) })))); conn.SendAsync(Arg.Any <HeartbeatRequest>(), Arg.Any <CancellationToken>(), Arg.Any <IRequestContext>()) .Returns(_ => Task.FromResult(new HeartbeatResponse(ErrorCode.NONE))); var config = new ConsumerConfiguration(heartbeatTimeout: TimeSpan.FromMilliseconds(heartbeatMilliseconds * 2)); var request = new JoinGroupRequest(TestConfig.GroupId(), config.GroupHeartbeat, "", ConsumerEncoder.Protocol, new [] { protocol }); var memberId = Guid.NewGuid().ToString("N"); var response = new JoinGroupResponse(ErrorCode.NONE, 1, protocol.protocol_name, memberId, memberId, new [] { new JoinGroupResponse.Member(memberId, new ConsumerProtocolMetadata("mine")) }); using (new GroupConsumer(router, request.group_id, request.protocol_type, response, config)) { await Task.Delay(totalMilliseconds); } Assert.That(conn.ReceivedCalls() .Count(c => { if (c.GetMethodInfo().Name != nameof(Connection.SendAsync)) { return(false); } var s = c.GetArguments()[0] as HeartbeatRequest; if (s == null) { return(false); } return(s.group_id == request.group_id && s.member_id == memberId && s.generation_id == response.generation_id); }), Is.InRange(expectedHeartbeats - 1, expectedHeartbeats + 1)); }