From Python To Go:�How Khan Academy is saving time and money
With your host, Steve Coffman
What is Khan Academy?
Who am I?
(not a brief philosophical interlude)
I love my job.�I love my co-workers.
I love what we do together.
Where did we start? �GCP App Engine �Python 2 Monolith
Where did we start? �GCP App Engine �Python 2 Monolith
This didn’t change. It’s awesome!
Where are we going?
GCP App Engine
Multiple Go Services (27)
GraphQL Between
Where are we going?
GCP App Engine
Multiple Go Services (27)
GraphQL Between
This didn’t change. It’s awesome!
EOL for Python 2 forced us to choose...
We Chose Go
What platform should we run on?
We Chose AppEngine (again)
Stick with Monolith or switch to services?
We Chose Services (27)
How do services communicate between each other?
We Chose GraphQL
How should we divide up into services?
Meet (some of) The 27 Services
user
districts
users
assignments
coaches
progress
render-server
analytics
content-library
content
Cloud Storage
graphql-gateway
How have we learned and transitioned to Go?
Learning Go at Khan
Ways to Safely Transition
Side-by-Side Transition at Khan
Side-by-Side
Side-by-Side
Side-by-Side
Side-by-Side
Side-by-Side
It’s code time!
GraphQL Schema Changes
Step 1: Python and beginning of Go
extend type Assignment @key(fields: "id") {
id: ID! @external
createdDate: Time�}
extend type Assignment @key(fields: "id") {
id: ID! @external
createdDate: Time @migrate(from: "python", state: "manual")
}
GraphQL Schema Changes
Step 2: Python and Go Side-by-Side
extend type Assignment @key(fields: "id") {
id: ID! @external
createdDate: Time @migrate(from: "python", state: "manual")
}
extend type Assignment @key(fields: "id") {
id: ID! @external
createdDate: Time @migrate(from: "python", state: "side-by-side")
}
Side-by-Side Differences
Side-by-Side Differences
Side-by-Side Differences
GraphQL Schema Changes
Step 3: Go serving, Python ignored
extend type Assignment @key(fields: "id") {
id: ID! @external
createdDate: Time @migrate(from: "python", state: "side-by-side")
}
extend type Assignment @key(fields: "id") {
id: ID! @external
createdDate: Time @migrate(from: "python", state: "migrated")
}
Side-by-Side GraphQL Schema Changes
Step 4: Go only, Python deleted
extend type Assignment @key(fields: "id") {
id: ID! @external
createdDate: Time @migrate(from: "python", state: "migrated")
}
extend type Assignment @key(fields: "id") {
id: ID! @external
createdDate: Time
}
Side-by-Side Transition at Khan
What about Mutations?
Blue/Green
Release a new version alongside the old version, then switch traffic.
Side-By-Side (Traffic Shadowing)
Release a new version alongside the old version.
Incoming traffic is mirrored to the new version and doesn't impact the response.
Canary
Release a new version to a subset of users, then proceed to a full rollout.
Canaries and You
Canaries and YOU
GraphQL Schema Changes
Step 1: Python and beginning of Go
extend type Assignment @key(fields: "id") {
id: ID! @external
createdDate: Time�}
extend type Assignment @key(fields: "id") {
id: ID! @external
createdDate: Time @migrate(from: "python", state: "canary", color: "red")
}
Canary GraphQL Schema Changes
Step 2: Go only, Python deleted
extend type Assignment @key(fields: "id") {
id: ID! @external
createdDate: Time @migrate(from: "python", state: "canary", color: "red")
}
extend type Assignment @key(fields: "id") {
id: ID! @external
createdDate: Time
}
Sooo…
What’s Next
49
Thanks! Any questions?