Improve support for learners disconnecting during task

Now it is possible for learners to disconnect in the middle of any page,
and other learners in their group will be immediately notified (as soon
as the websocket connection closes). They will be able to vote to continue
without the missing user, or will proceed immediately if that user was the
only missing vote. On the chatroom page, they will see a message informing
them that the user has disconnected. If the user disconnects between pages,
the heartbeat timer from the previous check-in is still used to handle that
case.

There is still not support for learners disconnecting prior to group
formation (this will work, learners in the next stage will detect them
dropping out before group formation, but will result in groups smaller
than the ideal size). This is the next disconnection work item.

This proved to be more time-consuming than expected primarily because the
websocket server is silently swallowing any and all exceptions, and simply
terminating all sockets on the channel with a "non-clean" close event as a
result. I didn't expect this and so was looking for workarounds for these
socket closes, which proved to be unnecessary once the exceptions were fixed.