-
Notifications
You must be signed in to change notification settings - Fork 116
Description
Suppose I have a server that can both receive messages from the client and push messages unprompted. My sense is that the most natural way to write it is
- Fork a thread (
push-thread) for pushing that callssendTextDataor similar. - Have the main thread (
pull-thread) callingreceiveDataMessageor similar. - In
pull-thread, catchCloseRequestand use it to killpush-thread.
But that's vulnerable to race conditions, because (afaict) it's possible for push-thread to try to send data in between pull-thread completing a close handshake and killing push-thread.
As-is, I can think of two ways around this.
- Don't use
receiveDataMessage. Just usereceiveand handle control messages manually. conn' = conn { connectionWrite = onClose conn.connectionWrite act }whereonClose oldWrite act msgschecks if any of themsgsis aCloseand callsactif so; then regardless it passes them all on tooldWrite.
I don't love either of these. As an alternative, can we have a hook intended for this use case, something like
data CloseInitiatedBy = CloseInitiatedByUs | CloseInitiatedByThem
connectionOnClose :: CloseInitiatedBy -> IO ()that gets called immediately before we send a close message?
(Though I think figuring out who initiated isn't possible right now... we'd could try something like connectionReceivedClose :: IORef Bool, but that could theoretically fail if both sides try to initiate around the same time. But that situation is already awkward because you might try to send two Close requests and one of them will throw an error. So I dunno, maybe it's fine? Or just not having CloseInitiatedBy in the hook and tell the user they need to figure this out if necessary?)