-
Notifications
You must be signed in to change notification settings - Fork 46
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Billing, Take 1 #374
Billing, Take 1 #374
Conversation
8e10b89
to
03bbfea
Compare
Signed-off-by: Sander Pick <[email protected]>
Signed-off-by: Sander Pick <[email protected]>
Signed-off-by: Sander Pick <[email protected]>
Signed-off-by: Sander Pick <[email protected]>
Signed-off-by: Sander Pick <[email protected]>
Signed-off-by: Sander Pick <[email protected]>
Signed-off-by: Sander Pick <[email protected]>
Signed-off-by: Sander Pick <[email protected]>
Signed-off-by: Sander Pick <[email protected]>
Signed-off-by: Sander Pick <[email protected]>
Signed-off-by: Sander Pick <[email protected]>
Signed-off-by: Sander Pick <[email protected]>
Signed-off-by: Sander Pick <[email protected]>
Signed-off-by: Sander Pick <[email protected]>
Signed-off-by: Sander Pick <[email protected]>
Signed-off-by: Sander Pick <[email protected]>
Signed-off-by: Sander Pick <[email protected]>
Signed-off-by: Sander Pick <[email protected]>
3116dd9
to
a50a2a3
Compare
Signed-off-by: Sander Pick <[email protected]>
Signed-off-by: Sander Pick <[email protected]>
Signed-off-by: Sander Pick <[email protected]>
Signed-off-by: Sander Pick <[email protected]>
Signed-off-by: Sander Pick <[email protected]>
Signed-off-by: Sander Pick <[email protected]>
Signed-off-by: Sander Pick <[email protected]>
Signed-off-by: Sander Pick <[email protected]>
Signed-off-by: Sander Pick <[email protected]>
Signed-off-by: Sander Pick <[email protected]>
Signed-off-by: Sander Pick <[email protected]>
Signed-off-by: Sander Pick <[email protected]>
Signed-off-by: Sander Pick <[email protected]>
Signed-off-by: Sander Pick <[email protected]>
Signed-off-by: Sander Pick <[email protected]>
Signed-off-by: Sander Pick <[email protected]>
cb51f12
to
e5c09c6
Compare
Signed-off-by: Sander Pick <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added some comments to the bits that are worth looking at.
Signed-off-by: Sander Pick <[email protected]>
b56aebc
to
170bb20
Compare
Nice! great work dude. just a couple questions
|
Nice, that sounds good. Should be relatively quick to add that feature. I'll make it an issue.
This just means we still account for stored data since that would be the easiest one to game. Since it's not reset, a user would not be able to add 5Gib, delete subscription, re-subscribe, add another 5 Gib. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wow @sanderpick, this is a biggie. I've tried to give at least a cursory glance over everything. Obviously I haven't dug deep into any of the possible edge cases etc, but your higher level comments were super helpful in assessing the overall goals. Two of my primary "concerns" (what to do about existing data, and user-scoped allocations - to come later), are pretty well addressed here (or there are concrete plans to address them.
To follow up on one of Andrew's comments though: What about the following scenario:
Developer creates account, accrues data storage up to free amount and then doesn't upgrade/create account. They leave. Now what? We don't want to hold onto that data forever right? Do we imagine a time limit on keeping it around? Maybe a notification that it will be cleaned out? In theory, they might re-create their account (which you've covered), and would expect their data to still be there for a time.
"buckets_pb_service.js", | ||
"buckets_pb.d.ts", | ||
"buckets_pb_service.d.ts" | ||
"api/bucketsd/pb/bucketsd_pb.js", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, this will require changes to the downstream consumers of these APIs. Easy update. One "fix" might be to include an index.js file in the main package folder that makes the exports a bit more ergonomic. I might create a ticket for this, as it is certainly not urgent, and will only affect "us".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wow, not sure what to say other than this is a huge amount of really great work. The high level design and thinking is sound, and the low level details are too many and too complex to have any real feedback, so let's get this thing deployed and see what happens! Seriously awesome work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tons of work! 🎉
Left some comments that you might be interested.
log.Debugf("unhandled event type: %s\n", event.Type) | ||
} | ||
|
||
c.Status(http.StatusOK) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@sanderpick , do you know what happen if we have some downtime and Stripe calls the webhook?
Will they retry?
If they do retries that sounds good, but we should also take care that we might receive retries (two or more times). If Stripe retries because they had a network problem, we might receive the same webhook call more than once.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, they do retry:
In live mode, Stripe attempts to deliver your webhooks for up to three days with an exponential back off. In the Events section of the Dashboard, you can view when the next retry will occur.
More info here. They also have this event monitoring tool that looks like it could be handy at some point.
Our event handling logic is idempotent, so duplicate events should not be a problem.
if ok && owner.StorageAvailable != -1 { | ||
owner.StorageUsed += delta | ||
owner.StorageAvailable -= delta | ||
owner.StorageDelta += delta |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Trying to make sense of both +=
. StorageDelta
is the cumulative delta of the API, and StorageUsed
the cumulative from "history"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, exactly. StorageUsed
is their total used storage. The StorageDelta
is the diff from the current request.
var isDB bool | ||
var err error | ||
switch method { | ||
case "/threads.pb.API/NewDB": |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unrleated of this PR, idea: we rely on gRPC APIs as strings. If we somewhat rename a gRPC identifier, many of our things will fail silently. Not only here, but other files and also other of our projects.
I'm not aware if there's a dynamic way to get the name using the generated code of the client.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, pretty fragile. Curious if there's a best practice for this kind of method matching. Will look around.
@carsonfarmer Good question. At some point we could track account activity and if it goes stale for a year or so, we send an email saying we'll delete the account. |
Thanks! Took a good bit of back and forth... it will nice to try it out and see what needs tweaking. |
Signed-off-by: Sander Pick <[email protected]>
Closes #276
Addresses #373 in part (the limits are not all in place)
This PR required a number of big structural changes, which is why the diff is so huge. I've commented on the bits that are worth looking at.
Understanding this requires some knowledge of how Stripe works with recurring metered subscriptions.
The Hub has four products:
Stripe only cares about units of a product. I derived the current unit values by considering that we should only notify Stripe about usage at the 1 cent resolution. For example, the smallest unit of storage we have is 5Gib / 100, which costs 1 cent. The first 100 of which are free, amounting to 5Gib free. The same logic is used for the other products.
Note: Currently, this functionality is only available at the developer level. After #315, I'll extend usage billing to their users.
The life-cycle of a customer and the various states they can arrive in are important to understand.
hub billing portal
to launch the customer portal where a payment method can be added.hub billing setup
hub billing status
to see relevant usage and status info, like...Here's what the customer portal looks like. I added the logo and our color scheme.