Off-by-one error in expiry calculation
When there are no messages to offer or send, DuplexOutgoingSession waits until the time returned by DatabaseComponent#getNextSendTime()
before checking again. That method returns the next expiry time, and the message won't become sendable until that time has passed. If DuplexOutgoingSession's check takes less than a millisecond, it may find that the expiry time has been reached but not passed, so the message isn't sendable yet. In that case the message won't be sent until the next keepalive is sent, which could take up to a minute.