diff --git a/posthog-node/benchmarks/rusha-vs-native.mjs b/posthog-node/benchmarks/rusha-vs-native.mjs new file mode 100644 index 00000000..af60755e --- /dev/null +++ b/posthog-node/benchmarks/rusha-vs-native.mjs @@ -0,0 +1,70 @@ +// @ts-check + +import { bench, run, summary } from "mitata"; +import { createHash } from "node:crypto" +import pkg from 'rusha'; +const { createHash: createHashRusha } = pkg; + +// eslint-disable-next-line +const LONG_SCALE = 0xfffffffffffffff + +// from https://github.com/PostHog/posthog-js-lite/blob/2baa794708d78d5d10940817c3768e47abe2da99/posthog-node/src/feature-flags.ts#L460-L465 +function _hashRusha(key, distinctId, salt = '') { + // rusha is a fast sha1 implementation in pure javascript + const sha1Hash = createHashRusha() + sha1Hash.update(`${key}.${distinctId}${salt}`) + return parseInt(sha1Hash.digest('hex').slice(0, 15), 16) / LONG_SCALE +} + +function _hash(key, distinctId, salt = '') { + const sha1Hash = createHash("sha1") + sha1Hash.update(`${key}.${distinctId}${salt}`) + return parseInt(sha1Hash.digest('hex').slice(0, 15), 16) / LONG_SCALE +} + +summary(() => { + bench("_hash with rusha", () => { + _hashRusha("test", "user_id") + }); + + bench("_hash with native", () => { + _hash("test", "user_id") + }); +}); + +await run(); + + +// !NODE +// node benchmarks/rusha-vs-native.mjs +// clk: ~3.99 GHz +// cpu: AMD Ryzen 7 7700 8-Core Processor +// runtime: node 22.11.0 (x64-linux) + +// benchmark avg (min … max) p75 p99 (min … top 1%) +// ------------------------------------------- ------------------------------- +// _hash with rusha 12.10 µs/iter 7.25 µs █ +// (4.66 µs … 1.27 ms) 116.62 µs █▄▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ +// _hash with native 547.04 ns/iter 435.45 ns █ +// (370.08 ns … 3.61 µs) 3.58 µs █▃▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + +// summary +// _hash with native +// 22.12x faster than _hash with rusha + +// !BUN +// bun benchmarks/rusha-vs-native.mjs +// clk: ~5.04 GHz +// cpu: AMD Ryzen 7 7700 8-Core Processor +// runtime: bun 1.1.37 (x64-linux) + +// benchmark avg (min … max) p75 p99 (min … top 1%) +// ------------------------------------------- ------------------------------- +// _hash with rusha 10.00 µs/iter 4.96 µs █ +// (2.60 µs … 2.78 ms) 45.85 µs ▂█▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ +// _hash with native 471.82 ns/iter 420.00 ns █ +// (370.00 ns … 949.79 µs) 1.99 µs █▆▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + +// summary +// _hash with native +// 21.19x faster than _hash with rusha diff --git a/posthog-node/package.json b/posthog-node/package.json index 43f2c1ed..195e97d1 100644 --- a/posthog-node/package.json +++ b/posthog-node/package.json @@ -23,12 +23,12 @@ "module": "lib/index.esm.js", "types": "lib/index.d.ts", "dependencies": { - "axios": "^1.7.4", - "rusha": "^0.8.14" + "axios": "^1.7.4" }, "devDependencies": { "@types/node": "^18.0.0", - "commander": "^9.3.0" + "commander": "^9.3.0", + "mitata": "^1.0.21" }, "keywords": [ "posthog", diff --git a/posthog-node/src/feature-flags.ts b/posthog-node/src/feature-flags.ts index 09b6eb5b..a31cf996 100644 --- a/posthog-node/src/feature-flags.ts +++ b/posthog-node/src/feature-flags.ts @@ -1,4 +1,4 @@ -import { createHash } from 'rusha' +import { createHash } from 'node:crypto' import { FeatureFlagCondition, FlagProperty, PostHogFeatureFlag, PropertyGroup } from './types' import { JsonType, PostHogFetchOptions, PostHogFetchResponse } from 'posthog-core/src' import { safeSetTimeout } from 'posthog-core/src/utils' @@ -458,8 +458,7 @@ class FeatureFlagsPoller { // # uniformly distributed between 0 and 1, so if we want to show this feature to 20% of traffic // # we can do _hash(key, distinct_id) < 0.2 function _hash(key: string, distinctId: string, salt: string = ''): number { - // rusha is a fast sha1 implementation in pure javascript - const sha1Hash = createHash() + const sha1Hash = createHash("sha1") sha1Hash.update(`${key}.${distinctId}${salt}`) return parseInt(sha1Hash.digest('hex').slice(0, 15), 16) / LONG_SCALE } diff --git a/posthog-node/src/types/rusha.d.ts b/posthog-node/src/types/rusha.d.ts deleted file mode 100644 index d29f8ae8..00000000 --- a/posthog-node/src/types/rusha.d.ts +++ /dev/null @@ -1,23 +0,0 @@ -// Adjusted from type definitions for rusha 0.8 -// Project: https://github.com/srijs/rusha#readme -// Definitions by: Jacopo Scazzosi -// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped -// Minimum TypeScript Version: 4.0 - -/// - -interface Hash { - update(value: string | number[] | ArrayBuffer | Buffer): Hash - digest(encoding?: undefined): ArrayBuffer - digest(encoding: 'hex'): string -} - -interface Rusha { - createHash(): Hash -} - -declare const Rusha: Rusha - -declare module 'rusha' { - export = Rusha -} diff --git a/posthog-node/tsconfig.json b/posthog-node/tsconfig.json index d0b3de1d..e184f38f 100644 --- a/posthog-node/tsconfig.json +++ b/posthog-node/tsconfig.json @@ -1,7 +1,7 @@ { "extends": "../tsconfig.json", "compilerOptions": { - "types": ["node", "rusha"], - "typeRoots": ["./node_modules/@types", "../node_modules/@types", "./src/types"] + "types": ["node"], + "typeRoots": ["./node_modules/@types", "../node_modules/@types"] } } diff --git a/yarn.lock b/yarn.lock index 5107a218..ee168136 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7942,6 +7942,11 @@ minizlib@^2.1.1: minipass "^3.0.0" yallist "^4.0.0" +mitata@^1.0.21: + version "1.0.21" + resolved "https://registry.yarnpkg.com/mitata/-/mitata-1.0.21.tgz#525828c6306a5243da65b4d0574956f2572ca432" + integrity sha512-5HnbQJpz0Ub/7x7lxaxPhd3U3zXr7rD+24FIgEp/hjVE5wz6ye/pQRBrgH3MUK8KLy/FfPy/yfZbpi0sbmsNFg== + mixin-deep@^1.2.0: version "1.3.2" resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" @@ -9223,11 +9228,6 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" -rusha@^0.8.14: - version "0.8.14" - resolved "https://registry.yarnpkg.com/rusha/-/rusha-0.8.14.tgz#a977d0de9428406138b7bb90d3de5dcd024e2f68" - integrity sha512-cLgakCUf6PedEu15t8kbsjnwIFFR2D4RfL+W3iWFJ4iac7z4B0ZI8fxy4R3J956kAI68HclCFGL8MPoUVC3qVA== - safe-array-concat@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.2.tgz#81d77ee0c4e8b863635227c721278dd524c20edb"