5 ms·
I always think it's amazing how much simpler your architecture can get if you don't move any and all state to some other service in the name of keeping your app
by valzam 5y ago
I always think it's amazing how much simpler your architecture can get if you don't move any and all state to some other service in the name of keeping your app stateless. Of course there are good reasons why the industry has moved towards stateless business logic services but with all the BEAM goodness (resiliency, hot code reload) it might be feasible to write apps that actually hold state again.
- mrkurt 5y agoApps with state are wonderful to work with. I'm pretty excited to build apps that cache in process and don't rely on 47 external services to do CRUD.
- robotmay 5y agoAgreed. Elixir/BEAM gives you some really interesting new ways of solving problems. A couple of years ago I built a subscription system that interacted with Stripe that only kept the state whilst a user was interacting with the system (used a GenServer as a read-through/write-through Stripe API cache that exited after they stopped using it). It was by far the least irritating subscription system I've ever worked on.
- cpursley 5y agoInteresting. Do you mind (and if you can) elaborate on how you model that subscription system?
- robotmay 5y agoSure thing! Basically I set out to use Stripe's built-in tools as much as possible, rather than duplicating the state on our side - storing partial data in your own DB is one of the biggest pain points of subscription systems in my experience. So for this app it didn't have a DB at all - Stripe was the source of truth. The way it worked was fairly straightforward: a user would click a link from their account area and it would include their Stripe customer ID in the request (all our users had already had accounts created due to our main booking system). The app then span up a new GenServer to represent that customer, which would pull down all the data it needed from Stripe's API as soon as it initialised. There was also some generic data stored in a "global" GenServer to cover stuff like plans etc (I can't remember how I had that refreshing, probably via webhooks). Then as the user went through the subscription process or management process, any changes they made would be made through calls to their own personal GenServer, which on write would first write to the Stripe API, then update its own cache with the new state returned from Stripe to ensure consistency. These GenServers were kept alive by a timer set on interactions with it, and would automatically shut down 30 minutes after the user stopped interacting with it, discarding all the data it held. Then when they next return, it fetches the state from Stripe again. It also listened for webhooks and would update running GenServer instances with data it received to ensure they were consistent, and just ignored any for users that weren't currently running. Overall I was really happy with it - it was really performant due to the data caching but also didn't suffer from staleness issues :)