Strangler Fig Migration Pattern in Python
Gradually reroute calls from a legacy service to a modern replacement using a runtime switch and feature detection.
Python code
31 linesfrom dataclasses import dataclass
@dataclass
class PaymentService:
def process(self, amount: float) -> str:
return f"Legacy processed ${amount:.2f}"
class StranglerFig:
def __init__(self):
self._new_service = None
def attach_new(self, service):
self._new_service = service
def process_payment(self, amount: float) -> str:
if self._new_service and self._new_service.is_available():
return self._new_service.process(amount)
return PaymentService().process(amount)
class ModernPayment:
def is_available(self) -> bool:
return True
def process(self, amount: float) -> str:
return f"Modern processed ${amount:.2f}"
if __name__ == "__main__":
fig = StranglerFig()
print(fig.process_payment(100.0))
fig.attach_new(ModernPayment())
print(fig.process_payment(150.0))
Output
Legacy processed $100.00
Modern processed $150.00
How it works
This pattern wraps the legacy and modern services behind a facade. The facade checks whether the modern service is available for each call; if it is, the call is forwarded there, otherwise it falls back to the legacy implementation. This allows you to incrementally migrate traffic without a big-bang rewrite. It's a classic strangler fig approach: the modern system gradually 'strangles' the old one while the interface stays stable for callers.
Common mistakes
- Forgetting to check availability before calling the modern service, which can crash when it's not deployed.
- Hard-coding the fallback logic in every caller instead of centralizing it in the facade.
- Not planning for a rollback path if the modern service misbehaves.
Variations
- Use a percentage-based reweighting (e.g., route 10% of traffic to the new service and ramp up over time).
- Wrap both services behind a common protocol/interface so the facade works with any implementation.
Real-world use cases
- Migrating a payments microservice to a new provider while keeping the old API intact for customers.
- Gradually rolling out a rewritten recommendation engine to a subset of users before full cutover.
- Replacing an in-house auth service with a third-party identity provider without changing downstream callers.
Sponsored
More from Microservices patterns
- BFF aggregation pattern: combine multiple service responses in Python easy
- Backward Compatible Schema Evolution in Python medium
- Bulkhead Thread Pool per Service Mock in Python medium
- CQRS with Separate Read and Write Repositories in Python medium
- Cache-Aside Pattern in Python: Per-Service Mock easy
- Consumer Driven Contract Pact Mock in Python medium
Keep learning
Related tutorials and quizzes for this topic.