Prerequisite: Familiarity with the concepts introduced in Part 7 — Phase2 Dual Write. Review it first if the terminology in this part is unfamiliar.
Phase 3 is the final act: 100% of traffic moves to microservices, Magento becomes a passive archive, and the platform runs entirely on Go microservices via GitOps. No PHP in the critical path. No Magento license renewal needed.
Answer-first: Phase 3 cutover executes an immediate 100% traffic shift for stable read services and a graduated ramp over 10 days for transactional services. Legacy Magento remains a hot standby for 30 days while automated ArgoCD gitops pipelines handle production deployments.
Phase 3 Cutover Spec: Belongs to the Composable Commerce Monolith Migration collection. Review the core pillar post for full details.
1. The 6-Week Cutover Calendar
The 6-week cutover calendar structures final traffic migration, starting with low-risk staging and graduating to 100% production traffic.
The 6-week cutover schedule structures the orderly transfer of live production traffic from legacy Magento to the Go microservice platform while establishing strict operational change-freeze windows and risk mitigation buffers:
Week 1–2: Customer Service → 100% microservices
Week 3–4: Catalog Service → 100% microservices
Week 5–6: Order Service → 25% → 50% → 75% → 100%
Week 7+: Magento hot standby (event bus stops, archive-service runs hourly)
Week 11: Magento decommissioned (Day 30 of hot standby)
By Week 5, Customer and Catalog services run completely on microservices and have sustained production workloads for 3+ weeks. Debezium binlog reverse sync for these domains is deactivated. Microservices operate as the single source of truth. Only Order Service undergoes a multi-step graduated ramp because order mutations dictate real-time financial ledgers and payment gateway authorizations.
2. Customer + Catalog: Immediate 100% Cutover
Customer and catalog domains undergo immediate 100% traffic cutover after Phase 1 and 2 dual-write synchronization validation.
In 2026 production cutovers, edge network routing utilizes Anycast BGP IP routing and Cloudflare / AWS Route53 weighted DNS records with 5-second Time-to-Live (TTL) values. TLS 1.3 0-RTT session resumption eliminates connection handshake latency, while automated API Gateway cache invalidation purges legacy monolith cache entries instantly.
The shell script below executes the 100% cutover for Customer Service, disabling reverse sync and launching the read-only archive pipeline:
#!/bin/bash
# week-1-customer-cutover.sh
echo "Week 1: Customer Service Full Cutover"
# Disable dual-write reverse sync for customer
kubectl patch configmap feature-flags -n production \
--patch '{"data": {"customer_magento_sync": "false"}}'
# Route 100% customer traffic to microservices
kubectl patch configmap feature-flags -n production \
--patch '{"data": {"customer_write": "true", "customer_read": "true", "customer_cutover": "true"}}'
# Start customer archive (hourly sync to Magento for 30 days)
curl -X POST "http://archive-service:8080/api/v1/start-archive" \
-d '{"domain": "customer", "interval_seconds": 3600}'
# Monitor for 7 days
./scripts/monitor-cutover.sh --service=customer --duration=604800
echo "Customer Service cutover complete. Monitoring for 7 days."
The archive service performs a one-way, read-only sync from microservice PostgreSQL to legacy Magento. Magento is rendered read-only, serving as a warm backup while fulfilling corporate audit compliance requirements.
3. Order Service: Graduated Traffic Ramp
Order Service traffic ramps incrementally from 10% to 25%, 50%, and 100% over four weeks to monitor payment processing stability.
Order Service cutover employs Argo Rollouts traffic management integrated with Prometheus metrics. If p99 latencies breach 200ms or 5xx HTTP error rates exceed 0.05% across a 2-minute window, automated circuit breaker rollbacks immediately restore traffic to previous stable revisions.
The Go gateway router snippet below demonstrates how request traffic is partitioned deterministically using consistent customer ID hashing:
// gateway-service/internal/router/order_router.go
func routeOrderRequest(c *gin.Context, clients *ServiceClients, flags *FlagStore) {
flag := flags.Get("order_cutover")
if !flag.Enabled || flag.Percentage == 0 {
// Phase 2 mode: all orders to Order Service with Magento sync
handleOrderViaMicroservice(c, clients.Order, true /* syncToMagento */)
return
}
// Graduated ramp: hash customer ID to determine routing
// (same customer always goes to same system during transition)
customerID := c.GetHeader("X-Customer-ID")
hash := fnv.New32a()
hash.Write([]byte(customerID))
bucket := hash.Sum32() % 100
if bucket < uint32(flag.Percentage) {
// This customer's orders go to microservice (no Magento sync)
handleOrderViaMicroservice(c, clients.Order, false /* cutover: no sync */)
} else {
// Still routing to Magento for this customer
proxyToMagento(c)
}
}
Consistent customer ID hashing prevents session fragmentation—ensuring all checkout requests from a specific customer route to a single authoritative backend throughout the migration window.
The ramp schedule for Order Service (Week 5–6):
| Day | Cutover % | Action on each step |
|---|---|---|
| Day 1 (Monday) | 25% | Enable flag, monitor for 3 days |
| Day 4 (Thursday) | 50% | Validate consistency, check DLQ=0, increment |
| Day 7 (Sunday) | 75% | Validate, check payment reconciliation |
| Day 10 (Wednesday) | 100% | Final cutover, disable Magento routing |
At each ramp milestone, four mandatory gate criteria must be satisfied:
- DLQ message count = 0 (zero unhandled events)
- p99 write latency < 200ms (Phase 3 SLA target)
- Payment reconciliation: zero discrepancy between microservice DB and payment gateway ledgers
- Zero customer complaints or failed checkout sessions
4. The Archive Service
The archive service extracts historical Magento order logs into read-only PostgreSQL data lakes for long-term audit compliance.
To guarantee legacy Magento state is preserved without accepting new mutations, legacy MySQL instances are placed into strict read-only mode via SET GLOBAL super_read_only = ON;. The Kubernetes manifest below deploys the archive service to execute hourly state snapshots:
# k8s/archive-service.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: archive-service
namespace: production
spec:
replicas: 2
template:
spec:
containers:
- name: archive-service
image: archive-service:v1.0.0
args: ["--final-sync", "--compress"]
env:
- name: MICRO_DB_HOST
value: "platform-db.production.svc.cluster.local"
- name: MAGENTO_DB_HOST
value: "magento-db.production.svc.cluster.local"
- name: ARCHIVE_INTERVAL
value: "3600" # 1 hour
- name: ARCHIVE_DOMAINS
value: "customer,catalog,order,inventory"
Archive service behavior:
- Runs once per hour
- Reads from microservice PostgreSQL (authoritative)
- Writes to Magento MySQL (archive only, Magento writes disabled)
- Compresses data (JSON → gzip) for long-term storage
- Stops automatically after 30 days (Day 30 = Magento decommission)
5. ArgoCD GitOps: The Deployment Model After Migration
ArgoCD GitOps continuously synchronizes Kubernetes cluster state with Git repositories, automating deployments and drift detection.
With legacy Magento decommissioned, production deployment management shifts entirely to ArgoCD GitOps. In modern cloud environments, GitOps establishes Git repositories as the immutable single source of truth for all Kubernetes cluster state, providing automated drift detection, automated reconciliation, and audit logs.
The complete automated delivery pipeline flow for microservice releases operates as follows:
1. Developer: git push to feature branch
2. GitLab CI:
a. Run unit tests + integration tests
b. Build Docker image → push to registry
c. Open MR → code review
3. MR merged to main:
a. CI runs full test suite
b. Builds image: order-service:v1.2.3
c. Updates GitOps repo:
git commit -m "Update order-service to v1.2.3"
# Changes: gitops/apps/order-service/overlays/production/kustomization.yaml
# From: newTag: v1.2.2
# To: newTag: v1.2.3
4. ArgoCD detects change in GitOps repo:
a. Kustomize build: base + production overlay
b. kubectl apply to production cluster
c. Rolling update: 1 pod at a time, health check between each
5. ArgoCD rollback if unhealthy:
git revert HEAD # Reverts the image tag in GitOps repo
ArgoCD detects revert → rolls back deployment automatically
No manual kubectl apply commands or SSH access to production nodes are permitted. Every production configuration state change is backed by an audited, signed Git commit.
6. Kustomize: Base + Overlays Pattern
Kustomize base and overlay configurations manage environment-specific parameters across development, staging, and production clusters.
To maintain environment consistency across development, staging, and production clusters without template bloat, services organize manifests into base and overlay layers:
gitops/apps/order-service/
├── base/
│ ├── deployment.yaml ← Common: service definition, port, probes
│ ├── service.yaml
│ ├── configmap.yaml ← Non-secret config
│ └── kustomization.yaml
└── overlays/
├── dev/
│ ├── kustomization.yaml
│ └── patch-replicas.yaml ← replicas: 1, resources: small
└── production/
├── kustomization.yaml
└── patch-replicas.yaml ← replicas: 3, resources: production-sized
The production overlay kustomization.yaml manifest configures production container image tags, replica patches, and ConfigMap/Secret generator hash suffixes:
# gitops/apps/order-service/overlays/production/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
patches:
- path: patch-replicas.yaml
images:
- name: order-service
newTag: v1.2.3 ← Updated by CI on every release
The base deployment.yaml manifest defines standardized container ports, readiness/liveness health probes, and CPU/memory resource allocations:
# gitops/apps/order-service/base/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: order-service
spec:
template:
spec:
containers:
- name: order-service
image: order-service # Tag set by overlay
ports:
- containerPort: 8001 # HTTP
- containerPort: 9001 # gRPC
livenessProbe:
grpc:
port: 9001
initialDelaySeconds: 10
periodSeconds: 30
readinessProbe:
httpGet:
path: /health
port: 8001
initialDelaySeconds: 5
periodSeconds: 10
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "512Mi"
cpu: "500m"
7. Sync Waves: Ordered Deployment
ArgoCD sync waves enforce strict deployment order, starting database migrations before rolling out dependent microservice pods.
ArgoCD Sync Waves assign explicit numeric priorities to Kubernetes manifests, ensuring database schema migrations and messaging middleware components achieve readiness before application service pods begin rolling update deployments:
# gitops/apps/order-service/base/deployment.yaml
metadata:
annotations:
argocd.argoproj.io/sync-wave: "2" # Wave 2: services start after wave 1
# gitops/infrastructure/databases/postgresql.yaml
metadata:
annotations:
argocd.argoproj.io/sync-wave: "0" # Wave 0: databases first
# gitops/infrastructure/dapr-components.yaml
metadata:
annotations:
argocd.argoproj.io/sync-wave: "1" # Wave 1: Dapr before services
Sync wave progression follows: Databases & Schema Migrations (Wave 0) → PubSub & Dapr Components (Wave 1) → Microservices (Wave 2) → API Gateway (Wave 3).
8. Performance Validation: The 10× Load Test
Performance validation subjects the new Go microservice architecture to 10x peak load tests, verifying sub-50ms checkout response times.
Prior to declaring Phase 3 final cutover complete, the microservice architecture must sustain 10× historical peak traffic during distributed stress testing. The K6 stress test script below simulates high-concurrency order creation workloads to validate p99 latency SLAs:
// tests/load/phase3-validation.js
import http from 'k6/http';
import { check } from 'k6';
export const options = {
stages: [
{ duration: '5m', target: 100 }, // Ramp up
{ duration: '10m', target: 1000 }, // 10× normal load
{ duration: '5m', target: 0 }, // Ramp down
],
thresholds: {
'http_req_duration': ['p99<200'], // 200ms p99 SLA
'http_req_failed': ['rate<0.001'], // < 0.1% error rate
},
};
export default function() {
// Test Order creation (the highest-risk endpoint)
const res = http.post('https://api.platform.com/api/v1/orders', JSON.stringify({
customer_id: randomCustomerID(),
items: [{ product_id: randomProductID(), quantity: 1 }],
shipping_address: testAddress(),
request_id: crypto.randomUUID(),
}));
check(res, { 'order created': (r) => r.status === 201 });
}
9. Magento Decommission: Day 30
Magento decommissioning takes place on Day 30 post-cutover, shutting down legacy PHP app servers and archiving old MySQL instances.
After maintaining 30 continuous days of zero-rollback production execution on Go microservices, legacy monolith decommissioning commences. Final database dumps (gzip SQL / compressed Parquet format) are uploaded to Amazon S3 Glacier with Object Lock compliance enabled, guaranteeing 7-year immutable data retention for regulatory compliance.
The shell script below executes final decommissioning, teardown of legacy Kubernetes namespaces, tombstoning of legacy DNS entries, and cleanup of gateway feature flag definitions:
#!/bin/bash
# day-30-decommission.sh
echo "Day 30: Decommissioning Magento hot standby"
# Step 1: Stop archive service
kubectl delete deployment archive-service -n production
# Step 2: Stop Debezium connector (if still running for any domain)
kubectl delete deployment sync-service -n migration
# Step 3: Export final Magento database backup
mysqldump --all-databases | gzip > /backup/magento-final-$(date +%Y%m%d).sql.gz
# Step 4: Shut down Magento application servers
kubectl delete namespace magento
# Step 5: Remove Magento feature flags from Gateway
kubectl patch configmap feature-flags -n production \
--type=json \
-p='[{"op": "remove", "path": "/data/catalog_read"},
{"op": "remove", "path": "/data/customer_read"},
{"op": "remove", "path": "/data/order_read"}]'
echo "✅ Magento decommissioned. Platform running 100% on microservices."
echo "💰 License savings: starting from next renewal cycle"
Phase 3 Completion Checklist
The completion checklist verifies 100% traffic routing to Go services, ArgoCD sync green status, and Magento server shutdown.
Week 5 (Order Service cutover complete):
- 10 consecutive days at 100% without auto-rollback
- Payment reconciliation: zero discrepancy between microservice and Magento ledgers
- DLQ message count: 0 throughout Week 5
Week 7 (Pre-decommission):
- Archive service running for 30 days without error
- Final load test: 10× production load, p99 < 200ms, error rate < 0.1%
- All domain teams sign off on migration completion
Day 30 (Decommission):
- Final Magento DB backup stored in long-term storage
- Magento infrastructure shutdown
- Feature flag Gateway config simplified
- Platform license renewal notification cancelled
What You’ve Built
You have successfully transformed a legacy monolithic Magento installation into 21 resilient, high-performance Go microservices.
After Phase 3, the platform is:
- 21 Go microservices on Kubernetes, deployed via ArgoCD GitOps
- Zero PHP in the critical request path
- Zero Magento license cost starting next renewal
- Independent scaling: Order Service scales independently during flash sales
- < 200ms p99 response time on all critical endpoints
- 30-day rollback capability → proven that rollback was never needed
Part 9 dives into the event reliability mechanism that made this migration possible without data loss: the Transactional Outbox + Saga pattern that guarantees every order event is delivered exactly once, and every failed transaction has a compensating action.
If you’re exploring similar distributed systems patterns, the Shopee Architecture Series documents how a regional super-app handles 10M+ concurrent users with a comparable microservices decomposition — useful reference for sizing and SLO decisions.
FAQ
Graduated traffic ramping during Phase 3 cutover minimizes operational risk when shifting live order processing to new Go microservices.
Why use ArgoCD GitOps instead of deploying directly with kubectl or Helm?
What does "zero-downtime cutover" actually guarantee?
How long should Magento run as a hot standby after cutover?
🔗 Next Step: Continue to Part 9 — Outbox Saga for the following module in the series.
