I’ve put together a simple coroutine that makes use of the WebSockets.jl package, but I’m not sure if WebSockets.jl (or the underlying HTTP.jl) is designed to be able to handle this sort of asynchronous behavior:
using WebSockets, Test
inbox = Channel{String}(10)
outbox = Channel{String}(10)
ws_task = @async WebSockets.open("wss://echo.websocket.org") do ws
@sync begin
inbox_task = @async while !eof(ws)
put!(inbox, String(read(ws)))
end
outbox_task = @async while isopen(ws)
write(ws, take!(outbox))
end
end
end
put!(outbox, "Hello")
put!(outbox, "World!")
@test take!(inbox) == "Hello"
@test take!(inbox) == "World!"
The tests above pass, but I’m still worried that simultaneous attempts to read(ws) and write(ws, "...") could interfere with one-another. If one of the read or write tasks is blocked, is it possible that performing the other task at the same time could leave the WebSocket in an inconsistent state?
Since you only have one writer and one reader, it’s probably fine. Those write and read calls are themselves blocking their respective tasks until completion, which is enough to ensure FIFO in each direction. If you add more writers or readers, then I might worry about out-of-order operations occurring.
Yes, I’ve been getting the same Workqueue inconsistency during testing on my machine.
The reason I originally included
finally
close(outbox)
end
was so that, if the websocket is closed by the websocket.org server, the close(outbox) call on exit from inbox_task would trigger the for outmsg in outbox loop to exit. This way the outbox_task will not wait indefinitely on an empty outbox channel even after the ws has been closed, and the @sync block in ws_task will be able to finish.