Skip to content
This repository has been archived by the owner on Nov 26, 2021. It is now read-only.

opus-training/dialog-engine

Repository files navigation

The StopCOVID Dialog Engine

The code in this repo is deployed on Amazon's serverless platform, using Lambda, Kinesis, DynamoDB, among other things. This was our first substantial experience writing a serverless app, and we were pleasantly surprised by how quickly we could create a useful app with well-defined, decoupled components. If you're curious about building serverless event-driven applications, have a look around this repo and copy what you'd like.

Architecture

The StopCOVID backend is serverless and event-driven. The core of the system is a Lambda function that receives commands from a Kinesis stream and produces events to a DynamoDB table and stream. Consumers of the event stream respond to the user and track per-user drill progress.

simplified architecture

A simplified overview of the StopCOVID architecture.

For a lot more detail, see the architecture overview.

The simulator

You can simulate the core of dialog processing on the command line — by feeding the dialog engine with command-line entries rather than entries from a kinesis stream. Try it out by running python simulator.py.

Interesting parts of the code

The heart of the system is in engine.py and, in particular, the process_command() function. Here you'll see how we process commands and churn out a series of events in response.

We aggressively adopted type checking. We used Python type hints wherever we could and we used the pyright type checker to enforce type hints. We also used Marshmallow schemas for everything that we serialized to or deserialized from JSON.

manage.py

The manage.py script contains commands that we've found helpful while operating the Dialog Engine in production. You'll need appropriate AWS credentials in your environment to use this script. Type python manage.py --help for info on what this script can do.

CI

We use black for code formatting and flake8 for linting, with a custom rule setting maximum line length to 100.

  • black --config black.toml .
  • flake8

Running tests

  • Run docker-compose up in the db_local directory
  • python -m unittest

localstack

To run dialog-engine (and scadmin) against local, mocked AWS infrastructure, we use localstack.

  1. Start localstack. This README & config assumes you'll run it in host mode on your machine (by passing the --host option), not using Docker. Make sure to include the configuration in .locastack-env. e.g.:
pip install localstack
set -a
. ./.localstack-env
set +a
localstack start --host
  1. Install serverless dependencies with npm i

  2. npm run deploy

  3. In scadmin, ensure the BOTO_ENDPOINT_URL env var is set

Notes

  • Running in host mode requires Java 8+--which you must install yourself--for DynamoDB to run
  • When restarting localstack in host mode, Kinesis/DynamoDB will sometimes end up in a corrupted state and/or fail to shut down, leaving lingering processes & blocked ports. Usually, manually stopping any java or kinesis-* processes will fix this, or removing the localstack infra directory (more details in this GitHub issue)
  • At time of writing, localstack Kinesis directly invokes Lambda functions (if they are linked to a stream) before returning a response to PUT record requests. If there are errors in the lambda invocation, this can result in confusing "timeouts" in the client PUTing records to Kinesis
  • The start npm script should work in theory, but is currently broken in practice: Cloudformation updates in localstack "fail" to deploy our lambdas (even though they successfully provision), so the deploy script always has an exit code of 1

SMS Client

After deploying dialog-engine to localstack, sms_client.py allows for direct interaction with dialog-engine as if actually sending & receiving SMS from a client application. Example steps:

  1. Start the api, dbq_consumer, and dialog_event_consumer docker-compose services in scadmin

  2. Start the client, e.g.: python sms_client.py http://localhost:4566 +15552345678

  3. Invite an employee at the same phone from step 2 using a locally running dashboard instance

  4. You should receive an invitation in your step 2 shell; send a message back

About

The dialog engine that powers SMS conversations for StopCovid.co

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published