Stripe Account

Metric

Target

RPO

n/a (no backups possible)

RTO

8 hours

Losing access to Stripe does not directly impact business continuity, however it prevents us from billing customers (who are billed via Stripe) and prevents new signups (via Stripe).

Cancelled Subscriptions

Subscriptions cannot be deleted in Stripe, even if an account has been deleted. But they can be cancelled, which is irreversible and prevents us from billing that customer via this subscription.

If a Subscription is cancelled, a new one will need to be created. The old subscription information would need to be manually copied over (i.e. associated product / price).

The new Subscription would need to be manually inserted into brain, and the cluster “moved” to it accordingly. This will require:

  1. Inserting it into the core.subscriptions table

  2. Setting core.clusters.subscription_id to the new one

Deleted Accounts (Customers)

A deleted Stripe customer is a big problem, as we immediately lose the payment method (CC) associated with this customer - the only way to restore that is to ask the customer to re-add it.

Nonetheless, re-creating a Customer would involve the following steps:

  1. Re-creating the customer in Stripe

  2. Updating core.stripe_customers.id for the organization

  3. Re-creating any cancelled Subscriptions (same as above)

  4. Informing the customer and asking for them to re-add their CC.

Deleted Products & Prices

This is tedious but possible.

Part 1: Restore products and prices

$ crash -U dev --hosts https://braindev.aks1.westeurope.azure.cratedb.net:4200
Password:
CONNECT OK
cr> SELECT * FROM core.product_pricing where offer = 'stripe';
+---------+--------+---------+--------+---------------------+-------------------+--------------------------------+----------------------+---------------------------+
| kind    | name   | tier    | offer  | plan                | region            | billing_dimension              | price_per_dtu_minute | min_per_billing_dimension |
+---------+--------+---------+--------+---------------------+-------------------+--------------------------------+----------------------+---------------------------+
| cluster | edge   | basic   | stripe | prod_JbO1EkQATqlHdZ | _default_         | price_1IyBFPJOpFszwfhBmXCp0aF8 |                    0 |                         1 |
| cluster | gp_v2  | premium | stripe | prod_IT3F155QzMr8dU | _default_         | price_1J8hqlJOpFszwfhBzxMupULv |               711187 |                         1 |
| cluster | gp_v2  | basic   | stripe | prod_IT3F155QzMr8dU | _default_         | price_1J7z9vJOpFszwfhBUoRaigg2 |               184932 |                         1 |
| cluster | so_v2  | basic   | stripe | prod_IT3p4dt6YIGsDO | _default_         | price_1J7zCVJOpFszwfhBNAQ3ldnr |               262557 |                         1 |
| cluster | io_v2  | basic   | stripe | prod_IT3r9dDRWciKHU | _default_         | price_1J7zBqJOpFszwfhBsmEjPLYF |               145890 |                         1 |
| cluster | mso    | pro     | stripe | prod_JlWVOLivXO4szi | _default_         | price_1J8hesJOpFszwfhBipLBX9KO |               794064 |                         1 |
| cluster | mso    | basic   | stripe | prod_JlWVOLivXO4szi | _default_         | price_1J7zSAJOpFszwfhBeADTCiYU |               411187 |                         1 |
| cluster | gp_v2  | pro     | stripe | prod_IT3F155QzMr8dU | _default_         | price_1J8hcbJOpFszwfhB2ED9mUHu |               362557 |                         1 |
| cluster | io_v2  | pro     | stripe | prod_IT3r9dDRWciKHU | _default_         | price_1J8hdYJOpFszwfhBqekdJTLU |               284932 |                         1 |
| cluster | so_v2  | pro     | stripe | prod_IT3p4dt6YIGsDO | _default_         | price_1J8heIJOpFszwfhBq0Hh6Nux |               511187 |                         1 |
| cluster | io_v2  | premium | stripe | prod_IT3r9dDRWciKHU | _default_         | price_1J8hrPJOpFszwfhBKPQOQZVd |               562557 |                         1 |
| cluster | so_v2  | premium | stripe | prod_IT3p4dt6YIGsDO | _default_         | price_1J8hryJOpFszwfhBr2zh0Qvr |               994064 |                         1 |
| cluster | mso    | premium | stripe | prod_JlWVOLivXO4szi | _default_         | price_1J8hsRJOpFszwfhBnMqs7dQS |              1531279 |                         1 |
| cluster | dev_v2 | basic   | stripe | prod_IVct7VwgPA9X75 | _default_         | price_1Idt3RJOpFszwfhBD2q0buaR |                15982 |                         1 |
| cluster | dev_v3 | basic   | stripe | prod_IVct7VwgPA9X75 | _default_         | price_1JNZkwJOpFszwfhBLNkf0d2I |                81050 |                         1 |
| cluster | dev_v3 | basic   | stripe | prod_IVct7VwgPA9X75 | aks1.eastus.azure | price_1JahtRJOpFszwfhBBtcmoz6V |                10000 |                         1 |
| cluster | io_v2  | basic   | stripe | prod_IT3r9dDRWciKHU | test.aws          | price_1JfPp9JOpFszwfhBpKudg9zC |               165890 |                         1 |
| cluster | io_v2  | basic   | stripe | prod_IT3r9dDRWciKHU | aks1.eastus.azure | price_1JfPp9JOpFszwfhBpKudg9zC |               185890 |                         1 |
+---------+--------+---------+--------+---------------------+-------------------+--------------------------------+----------------------+---------------------------+

Note

The example is for dev brain, but the prod brain is analogous.

The plan corresponds to a Product in Stripe, and the billing_dimension is the price within the Product. Most likely you will need to create new products / prices, and update the IDs in this table accordingly. Good luck :(

The price_per_dtu_minute to Stripe price calculation is in the CrateDB Cloud Pricing document in Sharepoint.

Part 2: Update core.cluster_billing_info

The core.cluster_billing_info table for running clusters will have old information about the plans and prices, and needs to be updated.

cr> SELECT b.*  FROM core.clusters c, core.cluster_billing_info b where c.is_deleted = false and c.id = b.cluster_id and b.offer = 'stripe' and b.name != 'edge';
+--------------------------------------+---------+--------+-------+--------+---------------------+-------------------+--------------------------------+----------------------+---------------------------+
| cluster_id                           | kind    | name   | tier  | offer  | plan                | region            | billing_dimension              | price_per_dtu_minute | min_per_billing_dimension |
+--------------------------------------+---------+--------+-------+--------+---------------------+-------------------+--------------------------------+----------------------+---------------------------+
| 242deafc-24e2-4875-9f70-c56a6d07f885 | cluster | dev_v3 | basic | stripe | prod_IVct7VwgPA9X75 | aks1.eastus.azure | price_1JahtRJOpFszwfhBBtcmoz6V |                10000 |                         1 |
| af9aa487-cf03-416d-9759-3f43eb34e968 | cluster | dev_v3 | basic | stripe | prod_IVct7VwgPA9X75 | aks1.eastus.azure | price_1JahtRJOpFszwfhBBtcmoz6V |                10000 |                         1 |
+--------------------------------------+---------+--------+-------+--------+---------------------+-------------------+--------------------------------+----------------------+---------------------------+

You get the picture: the plan and billing dimension have to be updated to match what’s in Stripe now.

Part 3: Add new prices to the subscriptions in Stripe

Now that the billing info table is updated, the consumption reporting will happen against the new prices. However, these prices also need to be added to the customer’s Stripe subscription for billing to work properly. First, get a list of affected subscriptions:

cr> SELECT s.id, s.reference, b.billing_dimension  FROM core.clusters c, core.cluster_billing_info b, core.subscriptions s where c.is_deleted = false and c.id = b.cluster_id and c.subscription_id = s.id and b.offer = 'stripe' and b.name !
    = 'edge';
+--------------------------------------+--------------------+--------------------------------+
| id                                   | reference          | billing_dimension              |
+--------------------------------------+--------------------+--------------------------------+
| e4721073-1080-47eb-99d5-9bd8d7d06995 | sub_JqU3tdWhMHMRFe | price_1JahtRJOpFszwfhBBtcmoz6V |
| 43a63c87-cd02-4173-91ad-1a1a2dd76612 | sub_JAS5dc2n5AJuxx | price_1JahtRJOpFszwfhBBtcmoz6V |
+--------------------------------------+--------------------+--------------------------------+

The reference is the Stripe subscription id. You can enter that into the Stripe dashboard’s Search field to go to the right subscription. Now go to Actions -> Update subscription and click on Add Product.

Now add the relevant price (billing_dimension) to the subscription:

../_images/edit_subscription.png

After this, billing should work. Double check the core.consumption_report table for the given subscription:

cr> SELECT * FROM core.consumption_report where subscription_id = 'sub_JqU3tdWhMHMRFe' order by from_ts desc limit 5;
+---------------+---------------+--------------------------------------+--------------------+-------------------+-------------------------------+
|       from_ts |         to_ts | cluster_id                           | subscription_id    | consumption_total | reporting_id                  |
+---------------+---------------+--------------------------------------+--------------------+-------------------+-------------------------------+
| 1641463745114 | 1641466802169 | 242deafc-24e2-4875-9f70-c56a6d07f885 | sub_JqU3tdWhMHMRFe |              51.0 | mbur_1KEtnAJOpFszwfhBrkLgR9ug |
| 1641304802448 | 1641307169735 | 8d71bd37-4b70-4bee-8592-a1069bac9ad4 | sub_JqU3tdWhMHMRFe |              39.0 | mbur_1KEEaMJOpFszwfhBrbP9ES0G |
| 1641301202205 | 1641304802448 | 8d71bd37-4b70-4bee-8592-a1069bac9ad4 | sub_JqU3tdWhMHMRFe |              60.0 | mbur_1KEDeaJOpFszwfhB6gu7r7xF |
| 1641297601637 | 1641301202205 | 8d71bd37-4b70-4bee-8592-a1069bac9ad4 | sub_JqU3tdWhMHMRFe |              60.0 | mbur_1KECiCJOpFszwfhBrHe66kyj |
| 1641294339920 | 1641297601637 | 8d71bd37-4b70-4bee-8592-a1069bac9ad4 | sub_JqU3tdWhMHMRFe |              54.0 | mbur_1KEBmFJOpFszwfhBKFNFjivH |
+---------------+---------------+--------------------------------------+--------------------+-------------------+-------------------------------+

There should be no entries with a NULL reporting_id after a consumption reporting job has run (they run every hour).