- The stack has five components:
vote(Flask),result(Node.js + Socket.IO),worker(C#/.NET),redis(queue), andpostgres(database). - App code for the three services is included in the repo under
vote/,result/, andworker/. Redis and Postgres are pulled from public images.

- vote (Flask)
- A lightweight Flask app presents two options (e.g., Cats vs Dogs).
- On submit, it generates a
voter_id, pushes a JSON payload into Redis (listvotes), and sets a cookie for the client. - The app listens on port
80and is served by Gunicorn in the production image.
- The example Dockerfile uses multi-stage builds to install dependencies in a base image, provide a development stage with file-watching, and produce a small runnable final image served by Gunicorn.
- worker (C#)
- The worker polls Redis
votes, processes each vote (e.g., de-duplicates or aggregates), and stores results in Postgres. - It connects to Redis at host
redisand Postgres at hostdbusing credentials in the demo.
- result (Node.js)
- The result service is a Node.js/Socket.IO server that reads aggregated state from Postgres and pushes updates to connected browsers in real time.
- It uses a Postgres connection string pointing to host
dbwith userpostgresand passwordpostgres(demo configuration).
This demo embeds Postgres credentials and connection strings directly in source code for simplicity. For production, always inject secrets via environment variables, a secrets manager, or your orchestration platform (e.g., Docker secrets, Kubernetes Secrets, HashiCorp Vault).
- From the repository root you can either build each service image manually or use
docker compose upif the repository includes a Compose file.
voting-app network:
What to expect
- Use the Vote UI to cast votes. The Flask app enqueues messages in Redis.
- The worker polls Redis, processes votes, and writes aggregated results to Postgres.
- The Result UI reads from Postgres and broadcasts updates to clients in real time via Socket.IO.
- Stop and remove containers, the network, and the volume: