Hey Folks, I am investigating an issue on Android...
# ktor
s
Hey Folks, I am investigating an issue on Android where when I attach an onUpload listener with streaming body (okhttp engine, ktor ver 3.2.3). The progress is shown to user in UI and this is the behaviour we see: - Progress rapidly in 1MB steps - pause - repeat - So things go rapidly from 1 .. 1.1 ... 1.9 .. 2 then pause Pinpointed it down to this: https://github.com/ktorio/ktor/blob/main/ktor-client/ktor-client-core/common/src/io/ktor/client/utils/ByteChannelUtils.kt#L24 writeFully impl:
Copy code
@OptIn(InternalAPI::class)
public suspend fun ByteWriteChannel.writeFully(value: ByteArray, startIndex: Int = 0, endIndex: Int = value.size) {
    writeBuffer.write(value, startIndex, endIndex)
    flushIfNeeded()
}

@InternalAPI
public suspend fun ByteWriteChannel.flushIfNeeded() {
    rethrowCloseCauseIfNeeded()

    if (autoFlush || writeBuffer.size >= CHANNEL_MAX_SIZE) flush()
}

with CHANNEL_MAX_SIZE = 1MB
Also the autoFlush variable is being ignored in GlobalScope.writer function even though true is passed. Honouring it would have made onUpload progress smoother at the cost of extra flush calls. This seems like a bug. So root cause seems to be that we are actually flushing to socket at 1MB steps which causes the pause. Any progress b/w MBs is synthetic. Flush optimisation is fine from a perf standpoint, reduces syscalls/copies But the UX effect is user sees abrupt rapid progress then halt at MB boundaries. Is there any workaround for this? to get a smoother upload progress (other than hacking my own)
a
That's an expected behavior of
onUpload
firing once per buffer chunk that Ktor hands to the OkHttp client (~1 MB at a time). You can animate the progress bar to make it smoother.
b
The ignoring of the autoFlush argument in that function does seem like a bug though. We have a high buffer here because the flush function is quite heavy when working with low-level operations.