public int doWork()
    {
        final long nowNs = nanoClock.nanoTime();
        cachedNanoClock.update(nowNs);
        dutyCycleTracker.measureAndUpdate(nowNs);

        final int workCount = commandQueue.drain(CommandProxy.RUN_TASK, Configuration.COMMAND_DRAIN_LIMIT);

        final long shortSendsBefore = shortSends.get();
        final int bytesSent = doSend(nowNs);
        int bytesReceived = 0;

        if (0 == bytesSent ||
            ++dutyCycleCounter >= dutyCycleRatio ||
            (controlPollDeadlineNs - nowNs < 0) ||
            shortSendsBefore < shortSends.get())
        {
            bytesReceived = controlTransportPoller.pollTransports();

            dutyCycleCounter = 0;
            controlPollDeadlineNs = nowNs + statusMessageReadTimeoutNs;
        }

        if (reResolutionCheckIntervalNs > 0 && (reResolutionDeadlineNs - nowNs) < 0)
        {
            reResolutionDeadlineNs = nowNs + reResolutionCheckIntervalNs;
            controlTransportPoller.checkForReResolutions(nowNs, conductorProxy);
        }

        return workCount + bytesSent + bytesReceived;
    }
@Test
    void shouldSendLastDataFrameAsHeartbeatWhenIdle()
    {
        final StatusMessageFlyweight msg = mock(StatusMessageFlyweight.class);
        when(msg.consumptionTermId()).thenReturn(INITIAL_TERM_ID);
        when(msg.consumptionTermOffset()).thenReturn(0);
        when(msg.receiverWindowLength()).thenReturn(ALIGNED_FRAME_LENGTH);

        publication.onStatusMessage(msg, rcvAddress, mockDriverConductorProxy);

        final UnsafeBuffer buffer = new UnsafeBuffer(ByteBuffer.allocateDirect(PAYLOAD.length));
        buffer.putBytes(0, PAYLOAD);

        appendUnfragmentedMessage(rawLog, 0, INITIAL_TERM_ID, 0, headerWriter, buffer, 0, PAYLOAD.length);

        sender.doWork();

        assertThat(receivedFrames.size(), is(1));  // should send ticks
        receivedFrames.remove();                   // skip data frame

        nanoClock.advance(Configuration.PUBLICATION_HEARTBEAT_TIMEOUT_NS - 1);
        sender.doWork();

        assertThat(receivedFrames.size(), is(0));  // should not send yet
        nanoClock.advance(10);
        sender.doWork();

        assertThat(receivedFrames.size(), greaterThanOrEqualTo(1));  // should send ticks

        dataHeader.wrap(receivedFrames.remove());
        assertThat(dataHeader.frameLength(), is(0));
        assertThat(dataHeader.termOffset(), is(offsetOfMessage(2)));
    }