Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
172 changes: 86 additions & 86 deletions docs/topics/algorithms.md

Large diffs are not rendered by default.

204 changes: 102 additions & 102 deletions docs/topics/database.md

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions docs/topics/distributed.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ Key distributed-systems building blocks and trade-offs, grouped by subtopic.
### Single-leader replication

- All writes go to one leader; [sync](https://www.postgresql.org/docs/current/warm-standby.html#SYNCHRONOUS-REPLICATION) followers are durable but add latency, async followers are fast but lose recent writes on failover.
- [Semi-sync](https://mariadb.com/docs/server/ha-and-performance/standard-replication/semisynchronous-replication) waits for at least one follower.
- [Semi-sync](https://dev.mysql.com/doc/refman/8.4/en/replication-semisync.html) waits for at least one follower.
- Replication lag breaks read-your-writes: a user can't see their own update right after writing.

### Multi-leader and leaderless
Expand Down Expand Up @@ -203,7 +203,7 @@ Key distributed-systems building blocks and trade-offs, grouped by subtopic.

### Change data capture

- [Log-based CDC](https://debezium.io/documentation/reference/stable/features.html) (Debezium) tails the [WAL](https://www.postgresql.org/docs/current/wal-intro.html) or [binlog](https://debezium.io/documentation/reference/stable/connectors/mysql.html): every committed change in commit order, deletes included, with no dual writes in the application.
- [Log-based CDC](https://debezium.io/documentation/reference/stable/features.html) (Debezium) tails the [WAL](https://www.postgresql.org/docs/current/wal-intro.html) or [binlog](https://dev.mysql.com/doc/refman/8.4/en/binary-log.html): every committed change in commit order, deletes included, with no dual writes in the application.
- Polling an `updated_at` column misses hard deletes and rows that commit late with an older timestamp.
- Bootstrap from a [consistent snapshot](https://debezium.io/documentation/reference/stable/connectors/postgresql.html#postgresql-snapshots), then stream from the log position it was taken at.
- Events are ordered per key (partition by primary key); connectors deliver at least once, so consumers must be idempotent.
Expand Down
126 changes: 63 additions & 63 deletions docs/topics/networking.md

Large diffs are not rendered by default.

136 changes: 68 additions & 68 deletions docs/topics/os.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion docs/topics/system.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ Key system design building blocks and trade-offs, grouped by subtopic. For CAP,
### Distributed rate limiting

- Enforce at the gateway, keyed by user, API key, or IP; reject with [429](https://www.rfc-editor.org/rfc/rfc6585#section-4) and [`Retry-After`](https://www.rfc-editor.org/rfc/rfc9110#field.retry-after).
- Share counters in Redis so every server sees one limit; wrap [`INCR`](https://redis.io/docs/latest/commands/incr/) + [`EXPIRE`](https://redis.io/docs/latest/commands/expire/) in [`MULTI`](https://redis.io/docs/latest/develop/interact/transactions/) or a [Lua script](https://redis.io/docs/latest/develop/interact/programmability/eval-intro/), or a crash between them leaves a counter with no TTL.
- Share counters in Redis so every server sees one limit; wrap [`INCR`](https://redis.io/docs/latest/commands/incr/) + [`EXPIRE`](https://redis.io/docs/latest/commands/expire/) in [`MULTI`](https://redis.io/docs/latest/develop/using-commands/transactions/) or a [Lua script](https://redis.io/docs/latest/develop/programmability/eval-intro/), or a crash between them leaves a counter with no TTL.
- A local per-instance limiter skips the round trip but is only approximate (limit ÷ instances).

## Reliability and operations
Expand Down
26 changes: 18 additions & 8 deletions scripts/check_links.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import pathlib
import re
import sys
import urllib.error
import urllib.parse
import urllib.request

Expand All @@ -18,18 +19,27 @@
LINK = re.compile(r"\]\((https?://[^)\s]+)\)")
# Minified HTML (the WHATWG spec, Hugo sites) leaves attribute values unquoted.
ANCHOR = re.compile(r"""(?<![\w-])(?:id|name)=(?:"([^"]+)"|'([^']+)'|([^\s"'>]+))""")
# Wikipedia rejects requests without a descriptive User-Agent.
USER_AGENT = "interview-briefs-link-checker (+https://github.com/pinebit/interviews)"
# Wikipedia rejects requests without a descriptive User-Agent; dev.mysql.com rejects
# agents it doesn't recognize, so a 403 is retried with urllib's default agent.
USER_AGENTS = ["interview-briefs-link-checker (+https://github.com/pinebit/interviews)", None]


def fetch(url):
"""Return (error, set of anchor ids) for a page URL without a fragment."""
request = urllib.request.Request(url, headers={"User-Agent": USER_AGENT})
try:
with urllib.request.urlopen(request, timeout=30) as response:
body = response.read().decode("utf-8", "replace")
except (OSError, http.client.HTTPException) as e: # URLError and timeouts are OSErrors
return str(e), set()
for user_agent in USER_AGENTS:
headers = {"User-Agent": user_agent} if user_agent else {}
try:
with urllib.request.urlopen(urllib.request.Request(url, headers=headers), timeout=30) as response:
body = response.read().decode("utf-8", "replace")
break
except urllib.error.HTTPError as e:
error = str(e)
if e.code != 403:
return error, set()
except (OSError, http.client.HTTPException) as e: # URLError and timeouts are OSErrors
return str(e), set()
else:
return error, set()
return None, {html.unescape("".join(groups)) for groups in ANCHOR.findall(body)}


Expand Down
Loading