anchor.diff:  let inline private simpleResponse (code: HttpCode) (message: string) =
       bytesResponse code (UTF8.bytes message)
   
  +/// Use CompareExchange to apply a mutation to a field.
  +/// Mutation must be pure & writes to the field should be rare compared to reads.
  +let mutateField<'t when 't: not struct> (targetField: 't byref) (mutation: 't -> 't) =
  +    let mutable retry = true
  +    while retry do
  +        let before = targetField
  +        let newValue = mutation before
  +        let afterExchange = System.Threading.Interlocked.CompareExchange(&targetField, newValue, before)
  +        retry <- not (obj.ReferenceEquals(before, afterExchange))
  +
   type EngineIo(config, app: EngineApp) =
       let mutable sessions: Map<SocketId, InternalEngineIoSocket> = Map.empty
       let idGenerator = Base64Id.create config.RandomNumberGenerator
       
  +    let socketTimeout = config.PingTimeout + config.PingInterval
  +    
  +    let socketClosed (socket: InternalEngineIoSocket) =
  +        ll.info (eventX (sprintf "Removing session with ID %s" (socket.Id.ToString())))
  +        mutateField &sessions (fun s -> s |> Map.remove socket.Id)
  +
       let payloadToResponse sid payload engineCtx =
           if engineCtx.SupportsBinary then
               bytesResponse HttpCode.HTTP_200 (payload |> Payload.encodeToBinary |> Segment.toArray)
  
positive.code: 
              match msg with
              | NewIncomming msg ->
                  logDebug (sprintf "[NewIncomming] %A" msg)
  
                  match msg with
  
negative.code:                     logDebug (sprintf "[ReadOutgoing] %i available" messages.Length)
                      rep.Reply(Payload(messages))
                      return! loop [] None
              | CloseOutgoing ->
                  logDebug "[CloseOutgoing] Closing"
                  return ()
          }
  
          loop [] None
      )
  
      let onMailBoxError (x: Exception) =
          logError (x.ToString())
          this.Close()
  
      do
          incomming.DefaultTimeout <- timeoutInMs * 2
          incomming.Error.Add(onMailBoxError)
          outgoing.DefaultTimeout <- timeoutInMs * 2
          outgoing.Error.Add(onMailBoxError)
          setPingTimeout ()
  
      member val Id = id
      member __.ReadIncomming() =
          lock closeLock (fun _ ->
              if closed then
                  Async.result None
              else
                  incomming.PostAndTryAsyncReply(ReadIncomming, timeoutInMs))
      member __.ReadOutgoing() =
          lock closeLock (fun _ ->
              if closed then
                  Async.result None
              else
                  outgoing.PostAndTryAsyncReply(ReadOutgoing, timeoutInMs))
      member __.AddOutgoing(msg) = outgoing.Post (NewOutgoing msg)
      member __.AddIncomming(msg) = incomming.Post (NewIncomming msg)
      member __.Close() =
          lock closeLock (fun _ ->
              if not closed then
                  closed <- true
                  onClose this
                  pingTimeoutTimer.Stop()
                  pingTimeoutTimer.Dispose()
                  incomming.Post CloseIncomming
                  outgoing.Post CloseOutgoing)
  
  type EngineIoSocket internal (socket: InternalEngineIoSocket) =
      member val Id = socket.Id
      member __.Read() = socket.ReadIncomming()
      member __.Send(msg) = socket.AddOutgoing(msg)
      member __.Close() = socket.Close()
  
  let inline private badAsync err = Async.result (Bad [err]) |> AR
  let inline private okAsync ok = Async.result (Ok(ok,[])) |> AR
  