Add ticket counters per raffle and measure the live site - #1
Merged
Merged
Conversation
The stress test gains a second ignored mode that drives a deployment named by STRESS_BASE_URL through its public API: a real checkout per sale, a Stripe test-mode confirmation with the Visa debit test card through the publishable key, and a poll of the order view every two seconds the way the confirmation page does. It reports checkout, confirmation and tickets-visible latencies per run. Run against donation.junaid.guru at the free capacity: 140 sales offered at 2, 5 and 10 a second were all allocated, tickets visible at the first poll up to 5 a second and a 4 second median at 10 a second. The README's scalability section carries the table. Stripe test mode's 25 requests a second cap the offered rate near 10 sales a second. reqwest is a dev-dependency of the webhook crate for this; the workspace build has no json feature, so bodies are parsed through text.
A third stress mode prepares orders through the checkout, then signs charge.succeeded events itself and posts them to the webhook's function URL, so the delivery rate is bounded by the stack rather than by Stripe's test-mode limit. It tallies the answers, polls every order for its tickets, and redelivers refused events once after five seconds as Stripe would. The endpoint and its signing secret come from the environment. Run against donation.junaid.guru: the counter drains about thirty allocations a second, a same-instant burst of forty already sheds one in eight to the retry budget, twenty a second goes through clean, and every refused event lands on redelivery. The README and the spec's ceiling now say so instead of the figure DynamoDB Local suggested.
The scalability section now carries one account of the stress test run against the live site: what the test does, the results, what they mean for a launch, what to change to handle more, and how to run it. The DynamoDB Local tables and the through-Stripe run are gone from the README; the shard bench keeps its own section.
The sharded counter's section now opens by stating that no function uses it and that every measurement above is of the single counter the site runs today, and it describes the alternative and its cost in plain terms.
A raffle row gains an optional shards count. Without it a raffle keeps today's single counter on its own row; with it, that many counter rows each own an equal share of the cap in their own partition, and the raffle's totals are the sum of the counters, read in one batch. One allocator serves both: it draws the next run from the raffle row or from the first counter with room, starting at the one the order id hashes to, and commits the same three-item transaction. Entries on a counter carry their shard and live in its partition with the same sort key, so who holds a ticket stays one query. The draw freezes one count per counter, picks one uniform number and maps it to a counter and a ticket by prefix sums; winners carry the shard. The reconciliation walks each counter's run against that counter. The admin takes the count at creation, writes the counters before the raffle, refuses to change the count or the cap afterwards, and lists and finds tickets by shard. The page and the console show a counter's ticket as 3-412. The spec records the setting and its ceiling, the README describes it plainly, and the stress test can be pointed at a named raffle.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this changes
A raffle can be created with several ticket counters. A raffle created without a count keeps today's single counter on its own row, which the live raffle has, so there is no migration. A raffle created with one gets that many counter rows, each with an equal share of the cap in its own partition; its totals are the sum of the counters, read in one batch. One allocator serves both, drawing the next run from the raffle row or from the first counter with room, starting at the one the order id hashes to, and committing the same three-item transaction. Entries carry their shard and live in the counter's partition with the same sort key, so who holds a ticket stays one query. The draw freezes one count per counter, picks one uniform number and maps it to a counter and a ticket by prefix sums. The reconciliation walks each counter's run. The admin console takes the count at creation, refuses to change it or the cap afterwards, pages the ledger counter by counter and finds a ticket as
3-412. The page shows a counter's ticket the same way.The stress test now runs against a deployment. With
STRESS_BASE_URLit pays real orders through Stripe test mode; withSTRESS_WEBHOOK_URLandSTRESS_WEBHOOK_SECRETas well it signscharge.succeededevents itself and posts them straight at the webhook, so the rate is bounded by the stack rather than by Stripe.STRESS_RAFFLE_IDpoints it at a named raffle.The README's scalability section is grounded in the live numbers. What the live site handled, what limits it, what to change to handle more, and how to run the test. The spec records the counters setting and its ceiling.
Measured on the live site, single counter
The counter drains about 30 paid orders a second; a same-instant burst of 40 already sheds one in eight to the retry budget; every refusal lands on redelivery.
After the merge
Create a demo raffle with eight counters through the console and run the direct stress test against it with
STRESS_RAFFLE_ID, to put the two tables side by side.Checks
cargo fmt --all --check,cargo clippy --workspace --all-targets --locked -- -D warningsandcargo test --workspace --lockedagainst DynamoDB Local all pass. New integration tests cover allocation under contention across counters, the draw across counters, the reconciliation walk, the admin's creation and refusals, and the shard on the order view.