Skip to content
Muhammet Şafak
tr
Asked by: Onur Answered:

How do I peel the payment module off a PHP monolith with Strangler Fig?


Question

I have a large PHP monolith. I want to peel off the "Payment" module and turn it into an independent Go microservice. I want to route traffic gradually (5%, 20%, 100%) to the new service without users or the existing code noticing. How do I set this up at the API Gateway (Envoy/Nginx) level? How do I keep consistency while splitting the databases?

Answer

Short answer: put a facade/gateway (Nginx/Envoy) in front, shift traffic by weight (5/20/100), keep the monolith as fallback. But the hard part isn’t routing — it’s the data.

The logic of Strangler Fig is this: you don’t kill the old module at once, you wrap it and slowly shift traffic to the new service. The order is:

  1. Set up weighted routing at the gateway. Keep Nginx/Envoy in front, send payment traffic to the new Go service by weight 5% → 20% → 100%, the rest to the monolith. If something blows up, the monolith fallback is ready; the rollback is one line of config.
  2. Run it in SHADOW first. Before it handles real money, run the new service in shadow mode: mirror traffic, compare outputs against the monolith’s, take no real action. If the numbers match, take it live. With money on the line there’s no “hope it’s right”.
  3. NEVER share tables. This is where the difficulty really is. Give the payment service its own store; don’t co-write into the monolith’s tables. Put an anti-corruption layer in between so the monolith’s model doesn’t leak into the new service.
  4. Keep consistency with outbox + events. Don’t reach for distributed transactions; write the change to your own DB, drop an outbox record in the same transaction, publish it as an event. Migrate data with dual-write + backfill, then reconcile, then cut over.
  5. Only extract a module with a clean boundary. If the payment module is tangled into the monolith’s tables, fix that seam first. If the boundary isn’t already clean, starting Strangler Fig just accelerates the disaster.

Bottom line: I’d set up weighted routing + monolith fallback at the gateway, validate the new Go service in shadow on mirrored traffic (not real money) first, then roll it out gradually. Don’t forget the real work is the data split, not the routing: no shared tables, an anti-corruption layer, consistency via outbox/events. I unpack the architectural depth on sade.dev — don’t try to peel off a module whose boundary isn’t clean.

Related Reading

Tags: #architecture#microservices#go
Share:

Comments

Sign in with your GitHub account to join the discussion. Comments are stored in GitHub Discussions.

More Questions

All questions

Search the site

Start typing to search posts, projects and pages.

Esc to close Powered by Pagefind