/dropcure

Toy project demonstrating WebSockets in Haskell

Primary LanguageHaskell

dropcure

dropcure was a take home assignment I did as part of a job interview. It consists of two services and one library.

  • producer - publishes messages received on websockets to a message queue.
  • consumer - broadbasts messages from the message queue to clients connected via websockets.
  • common - shared code for both services.

Overview

Both producer and consumer follow a similar pattern in that each implements a client and a server as a subcommand.

producer

Server

The producer server operates as follows:

  • Wait for RabbitMQ service to become available.
  • Connect to RabbitMQ server and create queue and channel if it doesn't exist.
  • Disconnect from RabbitMQ.
  • On new websocket connection:
    • Connect to RabbitMQ.
    • Send handshake message.
    • Repeatedly publish any message to RabbitMQ.

Client

The producer client is intended to be used for debugging purposes and operates as follows:

  • Connect to server.
  • Receive handshake.
  • Every n seconds emit a static message ("beep").

consumer

Sever

The consumer server operates as follows:

  • Initialise an empty mapping between unique identifiers and websocket.
  • Wait for RabbitMQ service to become available.
  • Connect to RabbitMQ server and create queue and channel if it doesn't exist.
  • Subscribe to the queue.
  • On new websocket connection:
    • Create unique identifier.
    • Add connection to mapping for given identifier.
  • On websocket disconnection:
    • Remove connection from mapping.
  • On new message in the queue:
    • Enumerate all connections in mapping and emit message via websockets.

Client

The consumer client is intended to be used for debugging purposes and operates as follows:

  • Connect to server.
  • Receive handshake.
  • On new message emitted by the server:
    • Print it to stdout.

Future Enhancements

Functionality

  • Handle situation when RabbitMQ goes down.

Testing

  • Add more tests.
  • Add mocks to test IO without doing IO as outlined in this blog post.

Operations

  • Add Docker build image so that it doesn't rely on the host OS being the same as the target.
  • Shrink Docker image e.g. use Alpine with glibc to keep the image sizes down.
  • Re-enable layer caching.

Usage

The instructions below assume that you are running Ubuntu, have Stack installed and have the Docker daemon running.

$ make up                             # start necessary services
$ WEBSOCKET_PORT=8001 consumer client # run the consumer client
$ WEBSOCKET_PORT=8000 producer client # run the producer client

Dependencies

  • docker
  • stack
  • ubuntu

Development

Tasks

% make
build                          Build producer and consumer Docker containers
clean                          Clean up build artefacts
help                           Print available tasks
install                        Compile producer and consumer
up                             Start services