Snowflakes
Nagbabalik ang GameVox ng IDs sa 64-bit snowflake format ng Discord saanman ito ginagawa ng Discord API. Pareho ang bit layout, sort order, at math ng pagkuha ng timestamp, kaya gumagana ang snowflake-parsing code mo nang walang binabago.
Format
Kapareho ng sa Discord: 42-bit timestamp + 5-bit worker + 5-bit process + 12-bit increment, big-endian sa loob ng 64-bit unsigned integer.
┌─ 42 bits ─────────────────┬─ 5 ─┬─ 5 ─┬─ 12 ────────┐
│ ms mula sa GameVox epoch │ wkr │ prc │ increment │
└───────────────────────────┴─────┴─────┴─────────────┘
63 22 21 17 16 12 11 0 Tugma sa Discord ang bawat segment:
- Timestamp (42 bits): milliseconds mula sa GameVox epoch, tingnan sa ibaba.
- Worker ID (5 bits): ina-assign sa bawat tumatakbong api task pag-startup gamit ang Redis atomic counter.
- Process ID (5 bits): ipinapares sa worker para sa isang unique na mint pool.
- Increment (12 bits): sequence kada millisecond kada (worker, process).
Epoch
Parehong epoch ng Discord ang gamit ng GameVox: 1420070400000 (2015-01-01 00:00:00 UTC). Gumagana sa GameVox IDs nang walang binabago ang snowflake parser na isinulat para sa Discord, walang constant na papalitan.
const SNOWFLAKE_EPOCH = 1420070400000n; Wire format
Bawat snowflake sa REST / gateway wire ay naka-serialize bilang JSON string, hindi number. Nawawalan ng precision ang JavaScript lampas sa Number.MAX_SAFE_INTEGER (253-1) at madalas lumampas doon ang snowflake. Laging i-parse gamit ang BigInt kapag kailangan mong mag-math, at i-store bilang string sa lahat ng iba pang lugar.
// Tama
const id = BigInt(message.id);
// Mali: tahimik na nawawala ang precision
const id = Number(message.id); Pagkuha ng timestamp
JavaScript
function snowflakeToDate(snowflake) {
const EPOCH = 1420070400000n; // pareho sa Discord
const ms = Number((BigInt(snowflake) >> 22n) + EPOCH);
return new Date(ms);
}
console.log(snowflakeToDate('182955831900192769'));
// → Date object: kung kailan na-mint ang snowflake na ito Python
from datetime import datetime, timezone
SNOWFLAKE_EPOCH = 1420070400000
def snowflake_to_dt(snowflake):
ms = (int(snowflake) >> 22) + SNOWFLAKE_EPOCH
return datetime.fromtimestamp(ms / 1000, tz=timezone.utc) Java
long SNOWFLAKE_EPOCH = 1420070400000L;
long ms = (Long.parseUnsignedLong(snowflake) >>> 22) + SNOWFLAKE_EPOCH;
Instant when = Instant.ofEpochMilli(ms); Pagkakasunod-sunod (sort order)
Dahil nasa high bits ang timestamp, ang lexicographic string comparison ng dalawang snowflake ay nag-o-order sa kanila ayon sa oras, gaya ng sa Discord. Ito ang dahilan kung bakit gumagana ang before / after / around pagination sa messages endpoint kahit walang explicit na timestamp field.
// Sa isang message array, pinakaluma → pinakabago:
messages.sort((a, b) => a.id < b.id ? -1 : a.id > b.id ? 1 : 0); Native data at ang alias table
Sa ilalim, UUIDv4 ang gamit ng GameVox-native objects (servers, channels, users, messages, atbp.). Nagmi-mint ang bot-compatibility layer ng stable na snowflake sa unang pagkakataong ma-expose ang object sa isang bot at sine-save ang pairing sa snowflake_aliases table. Lahat ng susunod na reference sa object na iyon, sa REST man o gateway, ay gagamit ng parehong snowflake.
Para sa messages, bina-backfill namin ang snowflakes gamit ang created_at ng message bilang source timestamp, kaya tama ang sort ng lumang messages kapag unang sumali ang bot sa channel. Para sa lahat ng iba, lazy na mini-mint ang alias sa unang exposure gamit ang NOW() bilang timestamp, kaya ipinapakita ng snowflake kung kailan nakita ng bot ang object, hindi kung kailan ito ginawa.
Sharding hash
Gumagana as-is ang standard na Discord shard formula:
shardId = (BigInt(guildId) >> 22n) % BigInt(numShards); Ang bots na wala pang 2,500 servers ay tumatakbo sa iisang shard ([0, 1]) at hindi na kailangang isipin ito. Ang mas malalaking bot ay makakakuha ng parehong medyo pantay na hash distribution na ibinibigay ng Discord, dahil time-monotonic ang top 42 bits, hindi random.
Mga gotcha
- Huwag i-compare ang snowflakes gamit ang
==laban sa number literal. Strings ang mga ito sa wire: i-compare sa string o i-convert pareho saBigInt. - Magra-wrap ang 42-bit timestamp mga 139 taon pagkatapos ng epoch. Valid ang snowflakes ng GameVox hanggang 2165.
- Huwag hulaan ang creation time ng server / channel / role mula sa snowflake nito. Ang native objects na mas nauna pa sa bot platform ay nakakuha ng snowflake sa unang bot exposure, hindi noong ginawa sila. Exception ang messages (bina-backfill gamit ang
created_at).