async def _send_resend_request(self, missing_seq_nums: List[int]): # Wait for opportunity to send resend request. Must: # # 1.) Have waited for resend requests from the target; and # 2.) Not be busy handling a resend request from the target if not self.waited_for_resend_request_event.is_set(): wait_time = self.startup_time + timedelta( seconds=SeqNumManagerApp.RESEND_WAIT_TIME ) wait_time = max(wait_time.timestamp() - datetime.utcnow().timestamp(), 0) logger.info( f"{self.name}: Waiting {wait_time:0.2f}s for ResendRequests from target " f"before doing gap fill..." ) await asyncio.sleep(wait_time) self.waited_for_resend_request_event.set() # Don't send our own resend requests if we are busy handling one received from the target await self.resend_request_handled_event.wait() # Separate task asyncio.create_task( self.send( admin.ResendRequestMessage(missing_seq_nums[0], missing_seq_nums[-1]) ) )
async def test_handle_resend_request_sends_resend_request( self, pipeline_with_messages ): seq_num_app = SeqNumManagerApp(pipeline_with_messages) seq_num_app.send_seq_num = 3 # 3 messages sent so far resend_begin_seq_num = 2 # Simulate resend request of 2 and 3 await seq_num_app._handle_resend_request( admin.ResendRequestMessage(resend_begin_seq_num) ) # Wait for separate 'send' tasks to complete tasks = asyncio.all_tasks() await asyncio.wait(tasks, timeout=0.1) assert pipeline_with_messages.send.call_count == 2 for idx in range(pipeline_with_messages.send.call_count): message = pipeline_with_messages.send.mock_calls[idx][1][0] # Check sequence number assert message.seq_num == resend_begin_seq_num + idx # Check PossDup flag assert bool(message.PossDupFlag) is True # Check sending time assert str(message.OrigSendingTime) == str(message.SendingTime)
async def test_handle_resend_request_converts_admin_messages_to_sequence_reset_messages( self, logon_message, pipeline_with_messages, messages ): seq_num_app = SeqNumManagerApp(pipeline_with_messages) admin_messages = [logon_message, HeartbeatMessage("test123")] # Inject admin messages messages = admin_messages + messages # Reset sequence numbers for idx, message in enumerate(messages): message.MsgSeqNum = idx + 1 message_store_app = pipeline_with_messages.apps[MessageStoreApp.name] await message_store_app.initialize() message_store_app.store._store.clear() for message in messages: await message_store_app.set_sent(message) seq_num_app.send_seq_num = max( message.seq_num for message in pipeline_with_messages.apps[ MessageStoreApp.name ].store._store.values() ) resend_begin_seq_num = 1 await seq_num_app._handle_resend_request( admin.ResendRequestMessage(resend_begin_seq_num) ) # Wait for separate 'send' tasks to complete tasks = asyncio.all_tasks() await asyncio.wait(tasks, timeout=0.1) assert pipeline_with_messages.send.call_count == 6 admin_messages_resend = pipeline_with_messages.send.mock_calls[0][1][0] # Check SequenceReset message is constructed correctly assert admin_messages_resend.seq_num == 1 assert int(admin_messages_resend.NewSeqNo) == 3 assert bool(admin_messages_resend.PossDupFlag) is True # Check first non-admin message starts with correct sequence number first_non_admin_message_resend = pipeline_with_messages.send.mock_calls[1][1][0] assert first_non_admin_message_resend.seq_num == 3