TASK
Implementation
A simple "rename column" migration breaks running app instances that still reference the old name. The expand-contract pattern avoids this: first add the new column (both columns exist simultaneously), then backfill the data, then remove the old column once all app instances are updated.
Implement a node that manages backward-compatible schema changes in three phases:
// Phase 1 — EXPAND: add new column (nullable, old column still present)
{ "type": "migrate", "msg_id": 1,
"phase": "expand", "table": "users", "add_column": "full_name" }
-> { "type": "migration_applied", "in_reply_to": 1,
"version": 1, "name": "add_full_name_column",
"schema": "users (name, full_name NULL)",
"backward_compatible": true }
// Phase 2 — DATA MIGRATION: copy name -> full_name for existing rows
{ "type": "migrate", "msg_id": 2,
"phase": "migrate_data", "from": "name", "to": "full_name" }
-> { "type": "data_migrated", "in_reply_to": 2,
"version": 2, "rows_migrated": 1000 }
// Phase 3 — CONTRACT: remove old column (only after all app instances updated)
{ "type": "migrate", "msg_id": 3,
"phase": "contract", "table": "users", "remove_column": "name" }
-> { "type": "migration_applied", "in_reply_to": 3,
"version": 3, "name": "remove_name_column",
"schema": "users (full_name)" }Sample Test Cases
Expand phase (add new column)Timeout: 5000ms
Input
{
"src": "admin",
"dest": "migrations",
"body": {
"type": "migrate",
"msg_id": 1,
"phase": "expand",
"table": "users",
"add_column": "full_name"
}
}Expected Output
{"type": "migration_applied", "in_reply_to": 1, "version": 1, "name": "add_full_name_column", "schema": "users (name, full_name NULL)", "backward_compatible": true}Data migration (backfill)Timeout: 10000ms
Input
{
"src": "admin",
"dest": "migrations",
"body": {
"type": "migrate",
"msg_id": 1,
"phase": "migrate_data",
"from": "name",
"to": "full_name"
}
}Expected Output
{"type": "data_migrated", "in_reply_to": 1, "version": 2, "rows_migrated": 1000}Hints
Hint 1▾
Expand: add the new column as nullable alongside the old one (both exist)
Hint 2▾
Migrate data: copy/transform values from old column to new column
Hint 3▾
Contract: remove the old column only after all app instances use the new column
Hint 4▾
Never rename or drop a column in a single migration with zero downtime
Hint 5▾
Rolling deployment: deploy new app version to instances one by one, health-checking each
OVERVIEW
Theoretical Hub
Concept overview coming soon
Key Concepts
expand-contract patternbackward compatibilityrolling deploymentcolumn renamezero downtime
main.py
python
1
2
3
4
5
6
7
8
9
10
11
12
13
#!/usr/bin/env python3
import sys
import json
def main():
# Your implementation here
for line in sys.stdin:
msg = json.loads(line)
print(json.dumps(msg), flush=True)
if __name__ == "__main__":
main()