Billing Platform Migrations @ Hootsuite
how we support multiple sources of billing information
Monetization platforms are the often overlooked key to collecting revenue from customers. These platforms are responsible for everything from storage of customer data (like billing addresses), to invoice generation and account balance tracking. At Hootsuite we use managed third-party services which can be costly, and sometimes impact our uptime because of the extra external dependency. Our desire for better predictability has spurred the adoption of a self-hosted solution, and a lengthy migration from our existing billing platform.
We began by re-tooling the account creation flow¹, which was the simplest option for getting users onto the new platform, and also carried the least risk. Groundwork for the new integration had already been built for an investigative exercise prior, so progress was only lacking on the front-end.
The choice of which billing form to load is managed by feature flags in Consul, a key-value store. In a nutshell, the flags control when and where we acquire users on the new platform. Eligibility is determined by geolocation because additional currencies and features, such as taxes, may need to be supported beforehand.
Developers use feature flags to switch between new and old billing flows, and to guard any changes made to them. Reverting modifications may consist of simply turning that flag off, bypassing the build pipeline and providing a safety net for our continuous integration. Additionally, having fine-grained controls allows billing smoke tests to cover the full gamut of platform-dependent flows. Generally, a feature is first launched on browser cookie mode before being completely enabled, so that quality assurance can be performed on the live environment without impacting customers. This is a necessary step because our test environments are linked to sandbox environments which are sometimes limited in their accuracy.
Meanwhile, the architectural distinction between the Dashboard, Billing Service, and billing platforms allows us to simultaneously offer support for both platforms from the backend. The Billing Service is written in Scala, and while it indexes all product plan variants, its other primary focus is linking a user’s Dashboard account to their billing platform account. It accomplishes this by storing their member id (the identifier used in the Dashboard), billing platform type, and corresponding platform account id.
To ease the addition of platform types, a CompositePlatform class is injected into the Billing Service’s internal services. It extends the trait, Platform, and relays the call to another Platform implementation corresponding to the user’s platform type. This would be SpecificPlatform in Figure 3. Billing Service can thereby handle requests dynamically, while consumers like the Dashboard can use the API without any knowledge of implementation details. Unfortunately, some billing areas have yet to emigrate from the Dashboard and still require knowledge of the user’s platform type. Events originating from platforms, such as overdue state changes, are all tagged with the platform type that generated the event, allowing the listener inside Billing Service to consume those in multiple ways as well.
Migrating existing accounts off of the old platform is a much more demanding problem. We built and honed an endpoint that scraped each bit of billing data from the old platform and added it to the newly created account in the other platform. Sometimes this required developing new features because 1-to-1 mappings did not exist between platforms. To perform migrations, users were selected through SQL queries and we fed them to our endpoint, writing results to log files and grouping any failed ones by their error code. This was effective for debugging, but lacked efficiency because it was a synchronous process. Gearman, a PHP job server, allowed for parallelization: one migration job was made per user⁴, and Gearman distributed jobs to workers. Results would instead be logged to Sumologic for analysis.
Hootsuite users deserve a billing experience with greater reliability and consistency — and that is the goal of the shift — but there are internal benefits as well. Self-hosting empowers the business to enhance the platform to adapt to the ever-changing technological landscape, and completing the migration unlocks the possibility of purging legacy billing flows tied to the old platform, a critical step in the overarching journey to decompose our Dashboard monolith. These internal benefits are what will enable us to deliver that improved experience.
About the Author
Cindy Hsu is a Computer Science Major at UBC. Fountain pen addict, video game enthusiast, and internet pop culture buff. Connect with her on LinkedIn.