Skip to content

Commit b8da315

Browse files
committed
Update 2nd group of articles to Table component
1 parent 0d44032 commit b8da315

21 files changed

Lines changed: 1252 additions & 650 deletions

File tree

‎.vscode/settings.json‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@
203203
"nicolaka",
204204
"Niklas",
205205
"noabbr",
206+
"Nobl",
206207
"nocache",
207208
"nodefs",
208209
"nohup",
@@ -222,6 +223,7 @@
222223
"oklch",
223224
"oncall",
224225
"Onest",
226+
"openslo",
225227
"optin",
226228
"PABC",
227229
"pacticipant",
@@ -231,6 +233,7 @@
231233
"Pgpool",
232234
"PGRST",
233235
"pids",
236+
"pkill",
234237
"Plaso",
235238
"pleroma",
236239
"plpgsql",
@@ -279,6 +282,7 @@
279282
"SIEM",
280283
"signup",
281284
"sklearn",
285+
"slis",
282286
"slsa",
283287
"slugified",
284288
"Southam",

‎src/content/articles/api-usage-metering-quotas-cost-attribution/index.mdx‎

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -141,12 +141,19 @@ Pick idempotency keys if you're using PostgreSQL or TimescaleDB—they support u
141141

142142
Most teams conflate rate limiting and quota enforcement. They're different tools for different problems:
143143

144-
| Mechanism | Time Window | Purpose |
145-
|-----------|-------------|---------|
146-
| Rate limiting | Per-second/minute | Protect infrastructure |
147-
| Quota enforcement | Per-day/month | Control costs |
148-
149-
Table: Rate limiting protects infrastructure; quotas control costs.
144+
<Table
145+
variant="vertical-column-delineation-table"
146+
content={{
147+
figure: "Rate limiting protects infrastructure; quotas control costs.",
148+
thead: { th: ["Mechanism", "Time Window", "Purpose"] },
149+
tbody: {
150+
tr: [
151+
{ th: "Rate limiting", td: ["Per-second/minute", "Protect infrastructure"] },
152+
{ th: "Quota enforcement", td: ["Per-day/month", "Control costs"] },
153+
],
154+
},
155+
}}
156+
/>
150157

151158
A consumer might have a rate limit of 100 requests per second (prevents overwhelming your API with bursts) and a monthly quota of 10 million requests (prevents consuming resources beyond their plan tier). You need both. The rate limit is infrastructure protection. The quota is cost control.
152159

‎src/content/articles/api-usage-metering-quotas-cost-attribution/pdf.mdx‎

Lines changed: 109 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -40,16 +40,23 @@ Not every metric needs to be billable, but you need to capture enough dimensions
4040

4141
The metrics that drive API costs:
4242

43-
| Dimension | Example | Cost Driver |
44-
|-----------|---------|-------------|
45-
| Request Count | 1.2M requests/month | Infrastructure scaling |
46-
| Data Transfer | 500 GB egress/month | Network costs |
47-
| Compute Time | 150 CPU-hours/month | Processing-intensive endpoints |
48-
| Storage | 50 GB stored | Persistent data APIs |
49-
| Unique Users | 10,000 MAU | License-based pricing |
50-
| Feature Usage | 500 report generations | Premium feature tracking |
51-
52-
Table: Common metering dimensions mapped to cost drivers.
43+
<Table
44+
variant="vertical-column-delineation-table"
45+
content={{
46+
figure: "Common metering dimensions mapped to cost drivers.",
47+
thead: { th: ["Dimension", "Example", "Cost Driver"] },
48+
tbody: {
49+
tr: [
50+
{ th: "Request Count", td: ["1.2M requests/month", "Infrastructure scaling"] },
51+
{ th: "Data Transfer", td: ["500 GB egress/month", "Network costs"] },
52+
{ th: "Compute Time", td: ["150 CPU-hours/month", "Processing-intensive endpoints"] },
53+
{ th: "Storage", td: ["50 GB stored", "Persistent data APIs"] },
54+
{ th: "Unique Users", td: ["10,000 MAU", "License-based pricing"] },
55+
{ th: "Feature Usage", td: ["500 report generations", "Premium feature tracking"] },
56+
],
57+
},
58+
}}
59+
/>
5360

5461
Request count is universal—every API tracks it. But it's often a poor proxy for cost. A 200-byte health check and a 50MB data export both count as "one request," but their infrastructure impact differs by orders of magnitude. Add data transfer and compute time to capture the actual resource consumption.
5562

@@ -224,15 +231,22 @@ Double-counting usage events leads to overbilling disputes and customer trust er
224231

225232
Quotas answer the question: "How much usage is too much?" But "too much" depends on context. A hard limit that rejects requests prevents runaway costs but creates a poor user experience. A soft limit that allows overages is forgiving but harder to predict financially. You need both, applied at different levels.
226233

227-
| Model | Behavior | Use Case |
228-
|-------|----------|----------|
229-
| Hard Limit | Reject requests over quota | Prevent runaway costs |
230-
| Soft Limit | Allow overage, bill extra | Usage-based pricing |
231-
| Burst Allowance | Allow temporary spikes | Handle legitimate traffic bursts |
232-
| Rolling Window | Reset over sliding period | Smooth usage patterns |
233-
| Token Bucket | Accumulate unused quota | Reward consistent usage |
234-
235-
Table: Quota enforcement models with use cases.
234+
<Table
235+
variant="vertical-column-delineation-table"
236+
content={{
237+
figure: "Quota enforcement models with use cases.",
238+
thead: { th: ["Model", "Behavior", "Use Case"] },
239+
tbody: {
240+
tr: [
241+
{ th: "Hard Limit", td: ["Reject requests over quota", "Prevent runaway costs"] },
242+
{ th: "Soft Limit", td: ["Allow overage, bill extra", "Usage-based pricing"] },
243+
{ th: "Burst Allowance", td: ["Allow temporary spikes", "Handle legitimate traffic bursts"] },
244+
{ th: "Rolling Window", td: ["Reset over sliding period", "Smooth usage patterns"] },
245+
{ th: "Token Bucket", td: ["Accumulate unused quota", "Reward consistent usage"] },
246+
],
247+
},
248+
}}
249+
/>
236250

237251
Hard limits are common for free tiers and trial accounts—once you hit the cap, you're done until the next billing period. Soft limits work for paid plans where you want to allow growth but charge for it. Burst allowances let consumers handle legitimate spikes (a batch job that runs monthly) without hitting a hard wall.
238252

@@ -258,12 +272,19 @@ Figure: Quota enforcement decision flow with soft limits and burst allowance.
258272

259273
Rate limiting and quota enforcement solve different problems. Rate limiting is "requests per second"—it protects infrastructure and ensures fairness. Quota enforcement is "requests per billing period"—it controls costs and enforces plan limits. You need both.
260274

261-
| Mechanism | Scope | Purpose |
262-
|-----------|-------|---------|
263-
| Rate Limiting | Per-second/minute | Protect infrastructure, ensure fairness |
264-
| Quota Enforcement | Per-day/month | Control costs, enforce plan limits |
265-
266-
Table: Rate limiting vs. quota enforcement—different tools for different problems.
275+
<Table
276+
variant="vertical-column-delineation-table"
277+
content={{
278+
figure: "Rate limiting vs. quota enforcement—different tools for different problems.",
279+
thead: { th: ["Mechanism", "Scope", "Purpose"] },
280+
tbody: {
281+
tr: [
282+
{ th: "Rate Limiting", td: ["Per-second/minute", "Protect infrastructure, ensure fairness"] },
283+
{ th: "Quota Enforcement", td: ["Per-day/month", "Control costs, enforce plan limits"] },
284+
],
285+
},
286+
}}
287+
/>
267288

268289
A consumer might have a rate limit of 100 requests per second but a monthly quota of 10 million requests. The rate limit prevents them from overwhelming your API with a sudden burst. The quota prevents them from consuming resources beyond their plan tier over the billing period.
269290

@@ -467,15 +488,22 @@ Most internal APIs start with direct attribution (simple to explain) then move t
467488

468489
Picking a cost model is as much psychology as math. The model shapes behavior—per-request pricing encourages consumers to reduce calls, compute-based pricing encourages efficient code, tiered pricing encourages growth.
469490

470-
| Model | Formula | Best For |
471-
|-------|---------|----------|
472-
| Per-Request | $0.001 × requests | Simple, predictable APIs |
473-
| Compute-Based | $0.10 × CPU-hours | Processing-intensive workloads |
474-
| Data Transfer | $0.05 × GB | Data-heavy APIs |
475-
| Tiered | Decreasing $/unit at volume | Encouraging growth |
476-
| Flat + Overage | $500/month + $0.001/request over 1M | Predictable base + flexibility |
477-
478-
Table: Cost models with formulas and use cases.
491+
<Table
492+
variant="vertical-column-delineation-table"
493+
content={{
494+
figure: "Cost models with formulas and use cases.",
495+
thead: { th: ["Model", "Formula", "Best For"] },
496+
tbody: {
497+
tr: [
498+
{ th: "Per-Request", td: ["$0.001 × requests", "Simple, predictable APIs"] },
499+
{ th: "Compute-Based", td: ["$0.10 × CPU-hours", "Processing-intensive workloads"] },
500+
{ th: "Data Transfer", td: ["$0.05 × GB", "Data-heavy APIs"] },
501+
{ th: "Tiered", td: ["Decreasing $/unit at volume", "Encouraging growth"] },
502+
{ th: "Flat + Overage", td: ["$500/month + $0.001/request over 1M", "Predictable base + flexibility"] },
503+
],
504+
},
505+
}}
506+
/>
479507

480508
The "Flat + Overage" model is underrated for internal APIs. It gives teams predictable budgets (the $500/month base covers normal usage) while preventing abuse (overages are billed separately). Finance likes it because budgets are stable, and engineering likes it because there's flexibility for legitimate spikes.
481509

@@ -561,14 +589,21 @@ Export this to CSV, send it to finance, and let them handle the budget transfers
561589

562590
There's a spectrum between "no cost visibility" and "full chargebacks." Most organizations benefit from moving gradually rather than jumping straight to chargebacks.
563591

564-
| Approach | Visibility | Budget Impact | Organizational Friction |
565-
|----------|------------|---------------|------------------------|
566-
| No Attribution | None | Hidden in shared costs | Low |
567-
| Showback | Full | Informational only | Low |
568-
| Soft Chargeback | Full | Budget guidance | Medium |
569-
| Hard Chargeback | Full | Actual cost transfer | High |
570-
571-
Table: Attribution approaches from visibility-only to hard chargebacks.
592+
<Table
593+
variant="vertical-column-delineation-table"
594+
content={{
595+
figure: "Attribution approaches from visibility-only to hard chargebacks.",
596+
thead: { th: ["Approach", "Visibility", "Budget Impact", "Organizational Friction"] },
597+
tbody: {
598+
tr: [
599+
{ th: "No Attribution", td: ["None", "Hidden in shared costs", "Low"] },
600+
{ th: "Showback", td: ["Full", "Informational only", "Low"] },
601+
{ th: "Soft Chargeback", td: ["Full", "Budget guidance", "Medium"] },
602+
{ th: "Hard Chargeback", td: ["Full", "Actual cost transfer", "High"] },
603+
],
604+
},
605+
}}
606+
/>
572607

573608
**Showback** means "here's what you're using, here's what it costs, but we're not moving money between budgets." It's pure visibility. Teams can see their consumption and optimize without financial pressure.
574609

@@ -738,16 +773,23 @@ Consumers need to see their usage in real-time, not when the bill arrives. A goo
738773

739774
The essential panels:
740775

741-
| Panel | Visualization | Purpose |
742-
|-------|---------------|---------|
743-
| Current Period Usage | Gauge/Progress | How much quota used |
744-
| Usage Trend | Time series | Daily/hourly usage pattern |
745-
| Usage by Endpoint | Bar chart | Which APIs drive usage |
746-
| Projected Month-End | Stat | Forecast based on current rate |
747-
| Cost Breakdown | Pie chart | Where money is going |
748-
| Alerts | List | Approaching limits, unusual patterns |
749-
750-
Table: Consumer-facing usage dashboard panels.
776+
<Table
777+
variant="vertical-column-delineation-table"
778+
content={{
779+
figure: "Consumer-facing usage dashboard panels.",
780+
thead: { th: ["Panel", "Visualization", "Purpose"] },
781+
tbody: {
782+
tr: [
783+
{ th: "Current Period Usage", td: ["Gauge/Progress", "How much quota used"] },
784+
{ th: "Usage Trend", td: ["Time series", "Daily/hourly usage pattern"] },
785+
{ th: "Usage by Endpoint", td: ["Bar chart", "Which APIs drive usage"] },
786+
{ th: "Projected Month-End", td: ["Stat", "Forecast based on current rate"] },
787+
{ th: "Cost Breakdown", td: ["Pie chart", "Where money is going"] },
788+
{ th: "Alerts", td: ["List", "Approaching limits, unusual patterns"] },
789+
],
790+
},
791+
}}
792+
/>
751793

752794
The layout matters. Put the most important information at the top—current usage and projected costs. Trends and breakdowns go below. Alerts go at the bottom unless they're critical (approaching quota), then promote them to the top.
753795

@@ -979,14 +1021,21 @@ The most common objection: "This will create budget battles between teams." True
9791021
9801022
Jumping straight to hard enforcement will cause significant organizational friction and backlash. A phased rollout lets you see your usage, understand the patterns, and optimize before financial consequences kick in.
9811023
982-
| Phase | Duration | Deliverable | Organizational Impact |
983-
|-------|----------|-------------|----------------------|
984-
| Instrument | 1-2 months | Metering pipeline | None (invisible) |
985-
| Report | 2-3 months | Showback dashboards | Awareness |
986-
| Soft Enforce | 1-2 months | Warnings at limits | Behavior change |
987-
| Hard Enforce | Ongoing | Quotas and billing | Budget impact |
988-
989-
Table: Phased rollout for API cost management implementation.
1024+
<Table
1025+
variant="vertical-column-delineation-table"
1026+
content={{
1027+
figure: "Phased rollout for API cost management implementation.",
1028+
thead: { th: ["Phase", "Duration", "Deliverable", "Organizational Impact"] },
1029+
tbody: {
1030+
tr: [
1031+
{ th: "Instrument", td: ["1-2 months", "Metering pipeline", "None (invisible)"] },
1032+
{ th: "Report", td: ["2-3 months", "Showback dashboards", "Awareness"] },
1033+
{ th: "Soft Enforce", td: ["1-2 months", "Warnings at limits", "Behavior change"] },
1034+
{ th: "Hard Enforce", td: ["Ongoing", "Quotas and billing", "Budget impact"] },
1035+
],
1036+
},
1037+
}}
1038+
/>
9901039
9911040
Soft Enforce warnings look like this:
9921041

‎src/content/articles/argocd-sync-failures-gitops-debugging-troubleshooting/index.mdx‎

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -68,14 +68,21 @@ Resources in the same wave apply in parallel. ArgoCD waits for all resources in
6868
6969
The wave numbers themselves are arbitrary—what matters is the relative order. Here's a pattern that works for most applications:
7070
71-
| Wave | Typical Resources | Purpose |
72-
|------|-------------------|---------|
73-
| -2 | Namespaces, CRDs | Infrastructure prerequisites |
74-
| -1 | Secrets, ConfigMaps | Configuration dependencies |
75-
| 0 | Deployments, Services | Main application (default) |
76-
| 1 | Jobs, migrations | Post-deployment tasks |
77-
78-
Table: Common sync wave ordering pattern.
71+
<Table
72+
variant="vertical-column-delineation-table"
73+
content={{
74+
figure: "Common sync wave ordering pattern.",
75+
thead: { th: ["Wave", "Typical Resources", "Purpose"] },
76+
tbody: {
77+
tr: [
78+
{ th: "-2", td: ["Namespaces, CRDs", "Infrastructure prerequisites"] },
79+
{ th: "-1", td: ["Secrets, ConfigMaps", "Configuration dependencies"] },
80+
{ th: "0", td: ["Deployments, Services", "Main application (default)"] },
81+
{ th: "1", td: ["Jobs, migrations", "Post-deployment tasks"] },
82+
],
83+
},
84+
}}
85+
/>
7986
8087
### Hooks Run Outside Normal Sync
8188
@@ -180,14 +187,21 @@ Use `--dry-run` to verify your fix before applying. Use `--hard-refresh` when Ar
180187

181188
Once you've gathered information, match it against these common patterns:
182189

183-
| Pattern | Symptom | Likely Cause | Quick Fix |
184-
|---------|---------|--------------|-----------|
185-
| Stuck on hook | "Running PreSync hooks" forever | Hook Job not completing | Check job logs, add `activeDeadlineSeconds` |
186-
| OutOfSync loop | Syncs successfully, immediately OutOfSync | Controller modifying resource | Add `ignoreDifferences` for that field |
187-
| Missing resource | "secret X not found" | Dependency ordering | Move dependency to earlier sync wave |
188-
| CRD not found | "server doesn't have resource type" | CRD applied too late | Put CRD in wave -5 |
189-
190-
Table: Common ArgoCD sync failure patterns with quick fixes.
190+
<Table
191+
variant="vertical-column-delineation-table"
192+
content={{
193+
figure: "Common ArgoCD sync failure patterns with quick fixes.",
194+
thead: { th: ["Pattern", "Symptom", "Likely Cause", "Quick Fix"] },
195+
tbody: {
196+
tr: [
197+
{ th: "Stuck on hook", td: ["\"Running PreSync hooks\" forever", "Hook Job not completing", "Check job logs, add `activeDeadlineSeconds`"] },
198+
{ th: "OutOfSync loop", td: ["Syncs successfully, immediately OutOfSync", "Controller modifying resource", "Add `ignoreDifferences` for that field"] },
199+
{ th: "Missing resource", td: ["\"secret X not found\"", "Dependency ordering", "Move dependency to earlier sync wave"] },
200+
{ th: "CRD not found", td: ["\"server doesn't have resource type\"", "CRD applied too late", "Put CRD in wave -5"] },
201+
],
202+
},
203+
}}
204+
/>
191205

192206
The "stuck on hook" pattern connects directly to the intro story—my production incident was exactly this. The hook was waiting for a dependency that didn't exist yet. Once you know to check hook job logs with `kubectl logs -l job-name=<hook>`, the cause usually becomes obvious.
193207

0 commit comments

Comments
 (0)