ninja-reverse-proxy 1.0.4 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +187 -139
- package/dist/balancer/contracts/balancer.interface.d.ts +8 -0
- package/dist/balancer/contracts/balancer.interface.d.ts.map +1 -0
- package/dist/balancer/contracts/balancer.interface.js +2 -0
- package/dist/balancer/contracts/balancer.interface.js.map +1 -0
- package/dist/balancer/contracts/context.types.d.ts +7 -0
- package/dist/balancer/contracts/context.types.d.ts.map +1 -0
- package/dist/balancer/contracts/context.types.js +2 -0
- package/dist/balancer/contracts/context.types.js.map +1 -0
- package/dist/balancer/contracts/strategy.interface.d.ts +6 -0
- package/dist/balancer/contracts/strategy.interface.d.ts.map +1 -0
- package/dist/balancer/contracts/strategy.interface.js +2 -0
- package/dist/balancer/contracts/strategy.interface.js.map +1 -0
- package/dist/balancer/core/load-balancer.d.ts +21 -0
- package/dist/balancer/core/load-balancer.d.ts.map +1 -0
- package/dist/balancer/core/load-balancer.js +188 -0
- package/dist/balancer/core/load-balancer.js.map +1 -0
- package/dist/balancer/core/strategy-registry.d.ts +8 -0
- package/dist/balancer/core/strategy-registry.d.ts.map +1 -0
- package/dist/balancer/core/strategy-registry.js +11 -0
- package/dist/balancer/core/strategy-registry.js.map +1 -0
- package/dist/balancer/factory/balancer.factory.d.ts +4 -0
- package/dist/balancer/factory/balancer.factory.d.ts.map +1 -0
- package/dist/balancer/factory/balancer.factory.js +35 -0
- package/dist/balancer/factory/balancer.factory.js.map +1 -0
- package/dist/balancer/index.d.ts +6 -0
- package/dist/balancer/index.d.ts.map +1 -0
- package/dist/balancer/index.js +3 -0
- package/dist/balancer/index.js.map +1 -0
- package/dist/balancer/strategies/adaptive-wrr.strategy.d.ts +8 -0
- package/dist/balancer/strategies/adaptive-wrr.strategy.d.ts.map +1 -0
- package/dist/balancer/strategies/adaptive-wrr.strategy.js +32 -0
- package/dist/balancer/strategies/adaptive-wrr.strategy.js.map +1 -0
- package/dist/balancer/strategies/consistent-hashing.strategy.d.ts +11 -0
- package/dist/balancer/strategies/consistent-hashing.strategy.d.ts.map +1 -0
- package/dist/balancer/strategies/consistent-hashing.strategy.js +45 -0
- package/dist/balancer/strategies/consistent-hashing.strategy.js.map +1 -0
- package/dist/balancer/strategies/ip-hash.strategy.d.ts +7 -0
- package/dist/balancer/strategies/ip-hash.strategy.d.ts.map +1 -0
- package/dist/balancer/strategies/ip-hash.strategy.js +24 -0
- package/dist/balancer/strategies/ip-hash.strategy.js.map +1 -0
- package/dist/balancer/strategies/least-connections.strategy.d.ts +6 -0
- package/dist/balancer/strategies/least-connections.strategy.d.ts.map +1 -0
- package/dist/balancer/strategies/least-connections.strategy.js +8 -0
- package/dist/balancer/strategies/least-connections.strategy.js.map +1 -0
- package/dist/balancer/strategies/least-response-time.strategy.d.ts +6 -0
- package/dist/balancer/strategies/least-response-time.strategy.d.ts.map +1 -0
- package/dist/balancer/strategies/least-response-time.strategy.js +8 -0
- package/dist/balancer/strategies/least-response-time.strategy.js.map +1 -0
- package/dist/balancer/strategies/power-of-two.strategy.d.ts +6 -0
- package/dist/balancer/strategies/power-of-two.strategy.d.ts.map +1 -0
- package/dist/balancer/strategies/power-of-two.strategy.js +17 -0
- package/dist/balancer/strategies/power-of-two.strategy.js.map +1 -0
- package/dist/balancer/strategies/random.strategy.d.ts +6 -0
- package/dist/balancer/strategies/random.strategy.d.ts.map +1 -0
- package/dist/balancer/strategies/random.strategy.js +8 -0
- package/dist/balancer/strategies/random.strategy.js.map +1 -0
- package/dist/balancer/strategies/resource-based.strategy.d.ts +7 -0
- package/dist/balancer/strategies/resource-based.strategy.d.ts.map +1 -0
- package/dist/balancer/strategies/resource-based.strategy.js +24 -0
- package/dist/balancer/strategies/resource-based.strategy.js.map +1 -0
- package/dist/balancer/strategies/round-robin.strategy.d.ts +7 -0
- package/dist/balancer/strategies/round-robin.strategy.d.ts.map +1 -0
- package/dist/balancer/strategies/round-robin.strategy.js +11 -0
- package/dist/balancer/strategies/round-robin.strategy.js.map +1 -0
- package/dist/balancer/strategies/sticky-sessions.strategy.d.ts +8 -0
- package/dist/balancer/strategies/sticky-sessions.strategy.d.ts.map +1 -0
- package/dist/balancer/strategies/sticky-sessions.strategy.js +20 -0
- package/dist/balancer/strategies/sticky-sessions.strategy.js.map +1 -0
- package/dist/balancer/strategies/weighted-least-connections.strategy.d.ts +6 -0
- package/dist/balancer/strategies/weighted-least-connections.strategy.d.ts.map +1 -0
- package/dist/balancer/strategies/weighted-least-connections.strategy.js +12 -0
- package/dist/balancer/strategies/weighted-least-connections.strategy.js.map +1 -0
- package/dist/balancer/strategies/weighted-round-robin.strategy.d.ts +8 -0
- package/dist/balancer/strategies/weighted-round-robin.strategy.d.ts.map +1 -0
- package/dist/balancer/strategies/weighted-round-robin.strategy.js +31 -0
- package/dist/balancer/strategies/weighted-round-robin.strategy.js.map +1 -0
- package/dist/cache/cache-manager.d.ts +25 -0
- package/dist/cache/cache-manager.d.ts.map +1 -0
- package/dist/cache/cache-manager.js +176 -0
- package/dist/cache/cache-manager.js.map +1 -0
- package/dist/cache/contracts/cache-config.interface.d.ts +25 -0
- package/dist/cache/contracts/cache-config.interface.d.ts.map +1 -0
- package/dist/cache/contracts/cache-config.interface.js +2 -0
- package/dist/cache/contracts/cache-config.interface.js.map +1 -0
- package/dist/cache/contracts/cache.interface.d.ts +8 -0
- package/dist/cache/contracts/cache.interface.d.ts.map +1 -0
- package/dist/cache/contracts/cache.interface.js +2 -0
- package/dist/cache/contracts/cache.interface.js.map +1 -0
- package/dist/cache/contracts/invalidator.interface.d.ts +6 -0
- package/dist/cache/contracts/invalidator.interface.d.ts.map +1 -0
- package/dist/cache/contracts/invalidator.interface.js +2 -0
- package/dist/cache/contracts/invalidator.interface.js.map +1 -0
- package/dist/cache/index.d.ts +3 -0
- package/dist/cache/index.d.ts.map +1 -0
- package/dist/cache/index.js +2 -0
- package/dist/cache/index.js.map +1 -0
- package/dist/cache/invalidation/debezium.invalidator.d.ts +8 -0
- package/dist/cache/invalidation/debezium.invalidator.d.ts.map +1 -0
- package/dist/cache/invalidation/debezium.invalidator.js +71 -0
- package/dist/cache/invalidation/debezium.invalidator.js.map +1 -0
- package/dist/cache/invalidation/pattern.invalidator.d.ts +9 -0
- package/dist/cache/invalidation/pattern.invalidator.d.ts.map +1 -0
- package/dist/cache/invalidation/pattern.invalidator.js +10 -0
- package/dist/cache/invalidation/pattern.invalidator.js.map +1 -0
- package/dist/cache/invalidation/tag.invalidator.d.ts +7 -0
- package/dist/cache/invalidation/tag.invalidator.d.ts.map +1 -0
- package/dist/cache/invalidation/tag.invalidator.js +17 -0
- package/dist/cache/invalidation/tag.invalidator.js.map +1 -0
- package/dist/cache/policies/cache-control.parser.d.ts +9 -0
- package/dist/cache/policies/cache-control.parser.d.ts.map +1 -0
- package/dist/cache/policies/cache-control.parser.js +18 -0
- package/dist/cache/policies/cache-control.parser.js.map +1 -0
- package/dist/cache/policies/key-builder.d.ts +11 -0
- package/dist/cache/policies/key-builder.d.ts.map +1 -0
- package/dist/cache/policies/key-builder.js +20 -0
- package/dist/cache/policies/key-builder.js.map +1 -0
- package/dist/cache/policies/stale-if-error.d.ts +4 -0
- package/dist/cache/policies/stale-if-error.d.ts.map +1 -0
- package/dist/cache/policies/stale-if-error.js +7 -0
- package/dist/cache/policies/stale-if-error.js.map +1 -0
- package/dist/cache/policies/stale-while-revalidate.d.ts +7 -0
- package/dist/cache/policies/stale-while-revalidate.d.ts.map +1 -0
- package/dist/cache/policies/stale-while-revalidate.js +13 -0
- package/dist/cache/policies/stale-while-revalidate.js.map +1 -0
- package/dist/cache/stores/hybrid.cache.d.ts +13 -0
- package/dist/cache/stores/hybrid.cache.d.ts.map +1 -0
- package/dist/cache/stores/hybrid.cache.js +36 -0
- package/dist/cache/stores/hybrid.cache.js.map +1 -0
- package/dist/cache/stores/in-memory-lru.d.ts +14 -0
- package/dist/cache/stores/in-memory-lru.d.ts.map +1 -0
- package/dist/cache/stores/in-memory-lru.js +41 -0
- package/dist/cache/stores/in-memory-lru.js.map +1 -0
- package/dist/cache/stores/redis.cache.d.ts +13 -0
- package/dist/cache/stores/redis.cache.d.ts.map +1 -0
- package/dist/cache/stores/redis.cache.js +39 -0
- package/dist/cache/stores/redis.cache.js.map +1 -0
- package/dist/config/config-schema.d.ts +3 -0
- package/dist/config/config-schema.d.ts.map +1 -0
- package/dist/config/config-schema.js +2 -0
- package/dist/config/config-schema.js.map +1 -0
- package/dist/config/config.d.ts +2 -0
- package/dist/config/config.d.ts.map +1 -0
- package/dist/config/config.js +2 -0
- package/dist/config/config.js.map +1 -0
- package/dist/config/config.loader.d.ts +266 -0
- package/dist/config/config.loader.d.ts.map +1 -0
- package/dist/config/config.loader.js +204 -0
- package/dist/config/config.loader.js.map +1 -0
- package/dist/config/index.d.ts +10 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +10 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/schemas/admin.schema.d.ts +7 -0
- package/dist/config/schemas/admin.schema.d.ts.map +1 -0
- package/dist/config/schemas/admin.schema.js +11 -0
- package/dist/config/schemas/admin.schema.js.map +1 -0
- package/dist/config/schemas/balancer.schema.d.ts +32 -0
- package/dist/config/schemas/balancer.schema.d.ts.map +1 -0
- package/dist/config/schemas/balancer.schema.js +52 -0
- package/dist/config/schemas/balancer.schema.js.map +1 -0
- package/dist/config/schemas/cache.schema.d.ts +25 -0
- package/dist/config/schemas/cache.schema.d.ts.map +1 -0
- package/dist/config/schemas/cache.schema.js +57 -0
- package/dist/config/schemas/cache.schema.js.map +1 -0
- package/dist/config/schemas/discovery.schema.d.ts +8 -0
- package/dist/config/schemas/discovery.schema.d.ts.map +1 -0
- package/dist/config/schemas/discovery.schema.js +13 -0
- package/dist/config/schemas/discovery.schema.js.map +1 -0
- package/dist/config/schemas/observability.schema.d.ts +48 -0
- package/dist/config/schemas/observability.schema.d.ts.map +1 -0
- package/dist/config/schemas/observability.schema.js +56 -0
- package/dist/config/schemas/observability.schema.js.map +1 -0
- package/dist/config/schemas/ratelimit.schema.d.ts +36 -0
- package/dist/config/schemas/ratelimit.schema.d.ts.map +1 -0
- package/dist/config/schemas/ratelimit.schema.js +51 -0
- package/dist/config/schemas/ratelimit.schema.js.map +1 -0
- package/dist/config/schemas/resilience.schema.d.ts +36 -0
- package/dist/config/schemas/resilience.schema.d.ts.map +1 -0
- package/dist/config/schemas/resilience.schema.js +91 -0
- package/dist/config/schemas/resilience.schema.js.map +1 -0
- package/dist/config/schemas/server.schema.d.ts +512 -0
- package/dist/config/schemas/server.schema.d.ts.map +1 -0
- package/dist/config/schemas/server.schema.js +104 -0
- package/dist/config/schemas/server.schema.js.map +1 -0
- package/dist/config/server-schema.d.ts +2 -0
- package/dist/config/server-schema.d.ts.map +1 -0
- package/dist/config/server-schema.js +2 -0
- package/dist/config/server-schema.js.map +1 -0
- package/dist/{server-schema.d.ts → core/cluster/ipc.protocol.d.ts} +4 -8
- package/dist/core/cluster/ipc.protocol.d.ts.map +1 -0
- package/dist/{server-schema.js → core/cluster/ipc.protocol.js} +5 -4
- package/dist/core/cluster/ipc.protocol.js.map +1 -0
- package/dist/core/cluster/master.d.ts +10 -0
- package/dist/core/cluster/master.d.ts.map +1 -0
- package/dist/core/cluster/master.js +875 -0
- package/dist/core/cluster/master.js.map +1 -0
- package/dist/core/cluster/worker.d.ts +2 -0
- package/dist/core/cluster/worker.d.ts.map +1 -0
- package/dist/core/cluster/worker.js +313 -0
- package/dist/core/cluster/worker.js.map +1 -0
- package/dist/core/pipeline/context.d.ts +12 -0
- package/dist/core/pipeline/context.d.ts.map +1 -0
- package/dist/core/pipeline/context.js +10 -0
- package/dist/core/pipeline/context.js.map +1 -0
- package/dist/core/pipeline/middleware.pipeline.d.ts +8 -0
- package/dist/core/pipeline/middleware.pipeline.d.ts.map +1 -0
- package/dist/core/pipeline/middleware.pipeline.js +18 -0
- package/dist/core/pipeline/middleware.pipeline.js.map +1 -0
- package/dist/core/proxy/connection.pool.d.ts +6 -0
- package/dist/core/proxy/connection.pool.d.ts.map +1 -0
- package/dist/core/proxy/connection.pool.js +18 -0
- package/dist/core/proxy/connection.pool.js.map +1 -0
- package/dist/core/proxy/http.handler.d.ts +18 -0
- package/dist/core/proxy/http.handler.d.ts.map +1 -0
- package/dist/core/proxy/http.handler.js +35 -0
- package/dist/core/proxy/http.handler.js.map +1 -0
- package/dist/core/proxy/upstream.client.d.ts +12 -0
- package/dist/core/proxy/upstream.client.d.ts.map +1 -0
- package/dist/core/proxy/upstream.client.js +13 -0
- package/dist/core/proxy/upstream.client.js.map +1 -0
- package/dist/core/proxy/websocket.handler.d.ts +12 -0
- package/dist/core/proxy/websocket.handler.d.ts.map +1 -0
- package/dist/core/proxy/websocket.handler.js +77 -0
- package/dist/core/proxy/websocket.handler.js.map +1 -0
- package/dist/core/router/route.matcher.d.ts +7 -0
- package/dist/core/router/route.matcher.d.ts.map +1 -0
- package/dist/core/router/route.matcher.js +16 -0
- package/dist/core/router/route.matcher.js.map +1 -0
- package/dist/core/router/route.types.d.ts +17 -0
- package/dist/core/router/route.types.d.ts.map +1 -0
- package/dist/core/router/route.types.js +2 -0
- package/dist/core/router/route.types.js.map +1 -0
- package/dist/core/router/router.d.ts +8 -0
- package/dist/core/router/router.d.ts.map +1 -0
- package/dist/core/router/router.js +14 -0
- package/dist/core/router/router.js.map +1 -0
- package/dist/discovery/contracts/registry.interface.d.ts +13 -0
- package/dist/discovery/contracts/registry.interface.d.ts.map +1 -0
- package/dist/discovery/contracts/registry.interface.js +2 -0
- package/dist/discovery/contracts/registry.interface.js.map +1 -0
- package/dist/discovery/health/active.probe.d.ts +10 -0
- package/dist/discovery/health/active.probe.d.ts.map +1 -0
- package/dist/discovery/health/active.probe.js +46 -0
- package/dist/discovery/health/active.probe.js.map +1 -0
- package/dist/discovery/health/health.manager.d.ts +18 -0
- package/dist/discovery/health/health.manager.d.ts.map +1 -0
- package/dist/discovery/health/health.manager.js +76 -0
- package/dist/discovery/health/health.manager.js.map +1 -0
- package/dist/discovery/health/passive.probe.d.ts +12 -0
- package/dist/discovery/health/passive.probe.d.ts.map +1 -0
- package/dist/discovery/health/passive.probe.js +12 -0
- package/dist/discovery/health/passive.probe.js.map +1 -0
- package/dist/discovery/index.d.ts +7 -0
- package/dist/discovery/index.d.ts.map +1 -0
- package/dist/discovery/index.js +6 -0
- package/dist/discovery/index.js.map +1 -0
- package/dist/{Serviceregistry.d.ts → discovery/registry/dynamic.registry.d.ts} +7 -3
- package/dist/discovery/registry/dynamic.registry.d.ts.map +1 -0
- package/dist/discovery/registry/dynamic.registry.js +138 -0
- package/dist/discovery/registry/dynamic.registry.js.map +1 -0
- package/dist/discovery/target-node.d.ts +12 -0
- package/dist/discovery/target-node.d.ts.map +1 -0
- package/dist/discovery/target-node.js +8 -0
- package/dist/discovery/target-node.js.map +1 -0
- package/dist/index.d.ts +0 -1
- package/dist/index.js +52 -17
- package/dist/index.js.map +1 -1
- package/dist/middleware/auth.middleware.d.ts +3 -0
- package/dist/middleware/auth.middleware.d.ts.map +1 -0
- package/dist/middleware/auth.middleware.js +15 -0
- package/dist/middleware/auth.middleware.js.map +1 -0
- package/dist/middleware/body-limit.middleware.d.ts +3 -0
- package/dist/middleware/body-limit.middleware.d.ts.map +1 -0
- package/dist/middleware/body-limit.middleware.js +12 -0
- package/dist/middleware/body-limit.middleware.js.map +1 -0
- package/dist/middleware/cache.middleware.d.ts +4 -0
- package/dist/middleware/cache.middleware.d.ts.map +1 -0
- package/dist/middleware/cache.middleware.js +16 -0
- package/dist/middleware/cache.middleware.js.map +1 -0
- package/dist/middleware/circuit.middleware.d.ts +3 -0
- package/dist/middleware/circuit.middleware.d.ts.map +1 -0
- package/dist/middleware/circuit.middleware.js +11 -0
- package/dist/middleware/circuit.middleware.js.map +1 -0
- package/dist/middleware/cors.middleware.d.ts +3 -0
- package/dist/middleware/cors.middleware.d.ts.map +1 -0
- package/dist/middleware/cors.middleware.js +19 -0
- package/dist/middleware/cors.middleware.js.map +1 -0
- package/dist/middleware/logging.middleware.d.ts +3 -0
- package/dist/middleware/logging.middleware.d.ts.map +1 -0
- package/dist/middleware/logging.middleware.js +9 -0
- package/dist/middleware/logging.middleware.js.map +1 -0
- package/dist/middleware/rate-limit.middleware.d.ts +4 -0
- package/dist/middleware/rate-limit.middleware.d.ts.map +1 -0
- package/dist/middleware/rate-limit.middleware.js +29 -0
- package/dist/middleware/rate-limit.middleware.js.map +1 -0
- package/dist/middleware/tracing.middleware.d.ts +3 -0
- package/dist/middleware/tracing.middleware.d.ts.map +1 -0
- package/dist/middleware/tracing.middleware.js +18 -0
- package/dist/middleware/tracing.middleware.js.map +1 -0
- package/dist/observability/health/readiness.d.ts +14 -0
- package/dist/observability/health/readiness.d.ts.map +1 -0
- package/dist/observability/health/readiness.js +23 -0
- package/dist/observability/health/readiness.js.map +1 -0
- package/dist/observability/index.d.ts +12 -0
- package/dist/observability/index.d.ts.map +1 -0
- package/dist/observability/index.js +8 -0
- package/dist/observability/index.js.map +1 -0
- package/dist/observability/logger/logger.d.ts +19 -0
- package/dist/observability/logger/logger.d.ts.map +1 -0
- package/dist/observability/logger/logger.js +83 -0
- package/dist/observability/logger/logger.js.map +1 -0
- package/dist/observability/logger/tenant-log.streamer.d.ts +29 -0
- package/dist/observability/logger/tenant-log.streamer.d.ts.map +1 -0
- package/dist/observability/logger/tenant-log.streamer.js +80 -0
- package/dist/observability/logger/tenant-log.streamer.js.map +1 -0
- package/dist/observability/metrics/histogram.registry.d.ts +43 -0
- package/dist/observability/metrics/histogram.registry.d.ts.map +1 -0
- package/dist/observability/metrics/histogram.registry.js +87 -0
- package/dist/observability/metrics/histogram.registry.js.map +1 -0
- package/dist/observability/metrics/prometheus.exporter.d.ts +19 -0
- package/dist/observability/metrics/prometheus.exporter.d.ts.map +1 -0
- package/dist/observability/metrics/prometheus.exporter.js +107 -0
- package/dist/observability/metrics/prometheus.exporter.js.map +1 -0
- package/dist/observability/metrics/system.metrics.d.ts +10 -0
- package/dist/observability/metrics/system.metrics.d.ts.map +1 -0
- package/dist/observability/metrics/system.metrics.js +20 -0
- package/dist/observability/metrics/system.metrics.js.map +1 -0
- package/dist/observability/tracing/tracer.d.ts +16 -0
- package/dist/observability/tracing/tracer.d.ts.map +1 -0
- package/dist/observability/tracing/tracer.js +24 -0
- package/dist/observability/tracing/tracer.js.map +1 -0
- package/dist/ratelimit/algorithms/fixed-window.d.ts +6 -0
- package/dist/ratelimit/algorithms/fixed-window.d.ts.map +1 -0
- package/dist/ratelimit/algorithms/fixed-window.js +20 -0
- package/dist/ratelimit/algorithms/fixed-window.js.map +1 -0
- package/dist/ratelimit/algorithms/leaking-bucket.d.ts +5 -0
- package/dist/ratelimit/algorithms/leaking-bucket.d.ts.map +1 -0
- package/dist/ratelimit/algorithms/leaking-bucket.js +17 -0
- package/dist/ratelimit/algorithms/leaking-bucket.js.map +1 -0
- package/dist/ratelimit/algorithms/sliding-window-counter.d.ts +5 -0
- package/dist/ratelimit/algorithms/sliding-window-counter.d.ts.map +1 -0
- package/dist/ratelimit/algorithms/sliding-window-counter.js +24 -0
- package/dist/ratelimit/algorithms/sliding-window-counter.js.map +1 -0
- package/dist/ratelimit/algorithms/sliding-window-log.d.ts +5 -0
- package/dist/ratelimit/algorithms/sliding-window-log.d.ts.map +1 -0
- package/dist/ratelimit/algorithms/sliding-window-log.js +16 -0
- package/dist/ratelimit/algorithms/sliding-window-log.js.map +1 -0
- package/dist/ratelimit/algorithms/token-bucket.d.ts +5 -0
- package/dist/ratelimit/algorithms/token-bucket.d.ts.map +1 -0
- package/dist/ratelimit/algorithms/token-bucket.js +19 -0
- package/dist/ratelimit/algorithms/token-bucket.js.map +1 -0
- package/dist/ratelimit/contracts/limiter.interface.d.ts +11 -0
- package/dist/ratelimit/contracts/limiter.interface.d.ts.map +1 -0
- package/dist/ratelimit/contracts/limiter.interface.js +2 -0
- package/dist/ratelimit/contracts/limiter.interface.js.map +1 -0
- package/dist/ratelimit/contracts/storage.interface.d.ts +6 -0
- package/dist/ratelimit/contracts/storage.interface.d.ts.map +1 -0
- package/dist/ratelimit/contracts/storage.interface.js +2 -0
- package/dist/ratelimit/contracts/storage.interface.js.map +1 -0
- package/dist/ratelimit/index.d.ts +16 -0
- package/dist/ratelimit/index.d.ts.map +1 -0
- package/dist/ratelimit/index.js +12 -0
- package/dist/ratelimit/index.js.map +1 -0
- package/dist/ratelimit/policies/multi-dimension.policy.d.ts +14 -0
- package/dist/ratelimit/policies/multi-dimension.policy.d.ts.map +1 -0
- package/dist/ratelimit/policies/multi-dimension.policy.js +13 -0
- package/dist/ratelimit/policies/multi-dimension.policy.js.map +1 -0
- package/dist/ratelimit/policies/soft-limit.policy.d.ts +8 -0
- package/dist/ratelimit/policies/soft-limit.policy.d.ts.map +1 -0
- package/dist/ratelimit/policies/soft-limit.policy.js +16 -0
- package/dist/ratelimit/policies/soft-limit.policy.js.map +1 -0
- package/dist/ratelimit/rate-limiter.d.ts +48 -0
- package/dist/ratelimit/rate-limiter.d.ts.map +1 -0
- package/dist/ratelimit/rate-limiter.js +420 -0
- package/dist/ratelimit/rate-limiter.js.map +1 -0
- package/dist/ratelimit/storage/hybrid.store.d.ts +10 -0
- package/dist/ratelimit/storage/hybrid.store.d.ts.map +1 -0
- package/dist/ratelimit/storage/hybrid.store.js +58 -0
- package/dist/ratelimit/storage/hybrid.store.js.map +1 -0
- package/dist/ratelimit/storage/memory.store.d.ts +8 -0
- package/dist/ratelimit/storage/memory.store.d.ts.map +1 -0
- package/dist/ratelimit/storage/memory.store.js +20 -0
- package/dist/ratelimit/storage/memory.store.js.map +1 -0
- package/dist/ratelimit/storage/redis.store.d.ts +10 -0
- package/dist/ratelimit/storage/redis.store.d.ts.map +1 -0
- package/dist/ratelimit/storage/redis.store.js +20 -0
- package/dist/ratelimit/storage/redis.store.js.map +1 -0
- package/dist/resilience/bulkhead/bulkhead.d.ts +11 -0
- package/dist/resilience/bulkhead/bulkhead.d.ts.map +1 -0
- package/dist/resilience/bulkhead/bulkhead.js +38 -0
- package/dist/resilience/bulkhead/bulkhead.js.map +1 -0
- package/dist/resilience/circuit-breaker/adaptive.circuit-breaker.d.ts +17 -0
- package/dist/resilience/circuit-breaker/adaptive.circuit-breaker.d.ts.map +1 -0
- package/dist/resilience/circuit-breaker/adaptive.circuit-breaker.js +33 -0
- package/dist/resilience/circuit-breaker/adaptive.circuit-breaker.js.map +1 -0
- package/dist/resilience/circuit-breaker/circuit-breaker.manager.d.ts +9 -0
- package/dist/resilience/circuit-breaker/circuit-breaker.manager.d.ts.map +1 -0
- package/dist/resilience/circuit-breaker/circuit-breaker.manager.js +22 -0
- package/dist/resilience/circuit-breaker/circuit-breaker.manager.js.map +1 -0
- package/dist/resilience/circuit-breaker/classic.circuit-breaker.d.ts +15 -0
- package/dist/resilience/circuit-breaker/classic.circuit-breaker.d.ts.map +1 -0
- package/dist/resilience/circuit-breaker/classic.circuit-breaker.js +39 -0
- package/dist/resilience/circuit-breaker/classic.circuit-breaker.js.map +1 -0
- package/dist/resilience/circuit-breaker/contracts/circuit-breaker.interface.d.ts +6 -0
- package/dist/resilience/circuit-breaker/contracts/circuit-breaker.interface.d.ts.map +1 -0
- package/dist/resilience/circuit-breaker/contracts/circuit-breaker.interface.js +2 -0
- package/dist/resilience/circuit-breaker/contracts/circuit-breaker.interface.js.map +1 -0
- package/dist/resilience/circuit-breaker/states/closed.state.d.ts +5 -0
- package/dist/resilience/circuit-breaker/states/closed.state.d.ts.map +1 -0
- package/dist/resilience/circuit-breaker/states/closed.state.js +7 -0
- package/dist/resilience/circuit-breaker/states/closed.state.js.map +1 -0
- package/dist/resilience/circuit-breaker/states/half-open.state.d.ts +5 -0
- package/dist/resilience/circuit-breaker/states/half-open.state.d.ts.map +1 -0
- package/dist/resilience/circuit-breaker/states/half-open.state.js +7 -0
- package/dist/resilience/circuit-breaker/states/half-open.state.js.map +1 -0
- package/dist/resilience/circuit-breaker/states/open.state.d.ts +5 -0
- package/dist/resilience/circuit-breaker/states/open.state.d.ts.map +1 -0
- package/dist/resilience/circuit-breaker/states/open.state.js +7 -0
- package/dist/resilience/circuit-breaker/states/open.state.js.map +1 -0
- package/dist/resilience/index.d.ts +13 -0
- package/dist/resilience/index.d.ts.map +1 -0
- package/dist/resilience/index.js +11 -0
- package/dist/resilience/index.js.map +1 -0
- package/dist/resilience/retry/backoff/decorrelated-jitter.backoff.d.ts +2 -0
- package/dist/resilience/retry/backoff/decorrelated-jitter.backoff.d.ts.map +1 -0
- package/dist/resilience/retry/backoff/decorrelated-jitter.backoff.js +7 -0
- package/dist/resilience/retry/backoff/decorrelated-jitter.backoff.js.map +1 -0
- package/dist/resilience/retry/backoff/equal-jitter.backoff.d.ts +2 -0
- package/dist/resilience/retry/backoff/equal-jitter.backoff.d.ts.map +1 -0
- package/dist/resilience/retry/backoff/equal-jitter.backoff.js +6 -0
- package/dist/resilience/retry/backoff/equal-jitter.backoff.js.map +1 -0
- package/dist/resilience/retry/backoff/exponential.backoff.d.ts +2 -0
- package/dist/resilience/retry/backoff/exponential.backoff.d.ts.map +1 -0
- package/dist/resilience/retry/backoff/exponential.backoff.js +4 -0
- package/dist/resilience/retry/backoff/exponential.backoff.js.map +1 -0
- package/dist/resilience/retry/backoff/full-jitter.backoff.d.ts +2 -0
- package/dist/resilience/retry/backoff/full-jitter.backoff.d.ts.map +1 -0
- package/dist/resilience/retry/backoff/full-jitter.backoff.js +5 -0
- package/dist/resilience/retry/backoff/full-jitter.backoff.js.map +1 -0
- package/dist/resilience/retry/contracts/retry.interface.d.ts +5 -0
- package/dist/resilience/retry/contracts/retry.interface.d.ts.map +1 -0
- package/dist/resilience/retry/contracts/retry.interface.js +2 -0
- package/dist/resilience/retry/contracts/retry.interface.js.map +1 -0
- package/dist/resilience/retry/retry-budget.d.ts +17 -0
- package/dist/resilience/retry/retry-budget.d.ts.map +1 -0
- package/dist/resilience/retry/retry-budget.js +37 -0
- package/dist/resilience/retry/retry-budget.js.map +1 -0
- package/dist/resilience/retry/retry-handler.d.ts +7 -0
- package/dist/resilience/retry/retry-handler.d.ts.map +1 -0
- package/dist/resilience/retry/retry-handler.js +24 -0
- package/dist/resilience/retry/retry-handler.js.map +1 -0
- package/dist/server.d.ts +5 -9
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +12 -645
- package/dist/server.js.map +1 -1
- package/dist/types/balancer.types.d.ts +18 -0
- package/dist/types/balancer.types.d.ts.map +1 -0
- package/dist/types/balancer.types.js +2 -0
- package/dist/types/balancer.types.js.map +1 -0
- package/dist/types/common.types.d.ts +11 -0
- package/dist/types/common.types.d.ts.map +1 -0
- package/dist/types/common.types.js +2 -0
- package/dist/types/common.types.js.map +1 -0
- package/dist/types/config.types.d.ts +8 -0
- package/dist/types/config.types.d.ts.map +1 -0
- package/dist/types/config.types.js +2 -0
- package/dist/types/config.types.js.map +1 -0
- package/dist/types/http.types.d.ts +14 -0
- package/dist/types/http.types.d.ts.map +1 -0
- package/dist/types/http.types.js +2 -0
- package/dist/types/http.types.js.map +1 -0
- package/dist/types/index.d.ts +7 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/resilience.types.d.ts +31 -0
- package/dist/types/resilience.types.d.ts.map +1 -0
- package/dist/types/resilience.types.js +2 -0
- package/dist/types/resilience.types.js.map +1 -0
- package/dist/types/upstream.types.d.ts +28 -0
- package/dist/types/upstream.types.d.ts.map +1 -0
- package/dist/types/upstream.types.js +2 -0
- package/dist/types/upstream.types.js.map +1 -0
- package/package.json +8 -2
- package/config.example.yaml +0 -99
- package/dist/Serviceregistry.d.ts.map +0 -1
- package/dist/Serviceregistry.js +0 -95
- package/dist/Serviceregistry.js.map +0 -1
- package/dist/auto-scaler.d.ts +0 -27
- package/dist/auto-scaler.d.ts.map +0 -1
- package/dist/auto-scaler.js +0 -133
- package/dist/auto-scaler.js.map +0 -1
- package/dist/cache.d.ts +0 -22
- package/dist/cache.d.ts.map +0 -1
- package/dist/cache.js +0 -112
- package/dist/cache.js.map +0 -1
- package/dist/config-schema.d.ts +0 -53
- package/dist/config-schema.d.ts.map +0 -1
- package/dist/config-schema.js +0 -78
- package/dist/config-schema.js.map +0 -1
- package/dist/config.d.ts +0 -47
- package/dist/config.d.ts.map +0 -1
- package/dist/config.js +0 -73
- package/dist/config.js.map +0 -1
- package/dist/health.d.ts +0 -5
- package/dist/health.d.ts.map +0 -1
- package/dist/health.js +0 -72
- package/dist/health.js.map +0 -1
- package/dist/loadBalancer.d.ts +0 -31
- package/dist/loadBalancer.d.ts.map +0 -1
- package/dist/loadBalancer.js +0 -171
- package/dist/loadBalancer.js.map +0 -1
- package/dist/metrics.d.ts +0 -14
- package/dist/metrics.d.ts.map +0 -1
- package/dist/metrics.js +0 -70
- package/dist/metrics.js.map +0 -1
- package/dist/rate-limiter.d.ts +0 -16
- package/dist/rate-limiter.d.ts.map +0 -1
- package/dist/rate-limiter.js +0 -59
- package/dist/rate-limiter.js.map +0 -1
- package/dist/server-schema.d.ts.map +0 -1
- package/dist/server-schema.js.map +0 -1
- package/monitoring/docker-compose.monitoring.yml +0 -22
- package/monitoring/prometheus.yml +0 -11
- package/monitoring/retry.t +0 -16
package/README.md
CHANGED
|
@@ -1,186 +1,234 @@
|
|
|
1
|
-
# Ninja Reverse Proxy
|
|
1
|
+
# 🛡️ Ninja Reverse Proxy
|
|
2
2
|
|
|
3
|
-
A production-grade, backend-agnostic **Layer 7 Reverse Proxy** built from scratch in TypeScript and Node.js.
|
|
3
|
+
A production-grade, backend-agnostic **Layer 7 Reverse Proxy & Load Balancer** built from scratch in TypeScript and Node.js.
|
|
4
4
|
|
|
5
|
-
Designed in the same philosophy as
|
|
5
|
+
Designed in the same engineering philosophy as **NGINX, Envoy, and HAProxy** — configure it once, point it at any backend, and it handles enterprise-grade traffic distribution, load balancing, rate limiting, multi-tier caching, resilience patterns, and health monitoring automatically.
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
9
|
-
##
|
|
9
|
+
## 🏛️ Master-Worker Architecture Overview
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
Ninja Reverse Proxy utilizes a highly performant **Master-Worker Cluster Architecture** that runs on all available CPU cores using Node.js Inter-Process Communication (IPC).
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
```
|
|
14
|
+
+----------------------------+
|
|
15
|
+
| Client (WS/HTTPS) |
|
|
16
|
+
+--------------+-------------+
|
|
17
|
+
|
|
|
18
|
+
▼
|
|
19
|
+
+----------------------------+
|
|
20
|
+
| Master Node (IPC Watchdog)|
|
|
21
|
+
+-------+------------+-------+
|
|
22
|
+
| |
|
|
23
|
+
(IPC Chans) (IPC Chans)
|
|
24
|
+
| |
|
|
25
|
+
+----------------v---+ +---v----------------+
|
|
26
|
+
| Worker 1 | | Worker 2 |
|
|
27
|
+
| - HTTP/WS Pipeline | | - HTTP/WS Pipeline |
|
|
28
|
+
| - L1 In-Memory LRU | | - L1 In-Memory LRU |
|
|
29
|
+
+-------+------------+ +---+----------------+
|
|
30
|
+
| |
|
|
31
|
+
(TCP/WSS Proxy) (TCP/WSS Proxy)
|
|
32
|
+
| |
|
|
33
|
+
+-------------v---------------------v-------------+
|
|
34
|
+
| Shared Distributed Tier: |
|
|
35
|
+
| - L2 Response Cache (Redis) |
|
|
36
|
+
| - Distributed Rate Limiter State (Redis Lua) |
|
|
37
|
+
| - Telemetry & Dynamic Service Registry |
|
|
38
|
+
| - Debezium CDC Invalidation Stream |
|
|
39
|
+
+------+------------------------------------+-----+
|
|
40
|
+
| |
|
|
41
|
+
▼ ▼
|
|
42
|
+
+--------------+ +--------------+
|
|
43
|
+
| Upstream A | | Upstream B |
|
|
44
|
+
+--------------+ +--------------+
|
|
45
|
+
```
|
|
14
46
|
|
|
15
47
|
---
|
|
16
48
|
|
|
17
|
-
##
|
|
18
|
-
|
|
19
|
-
| Feature | Details |
|
|
20
|
-
|---|---|
|
|
21
|
-
| Cluster Architecture | Master/Worker pattern via Node.js cluster — uses all CPU cores |
|
|
22
|
-
| Round-Robin Load Balancing | Equal request distribution across healthy upstreams |
|
|
23
|
-
| Circuit Breaker | Marks upstreams DOWN after configurable failure threshold |
|
|
24
|
-
| Redis Response Cache | GET response caching with configurable TTL |
|
|
25
|
-
| Per-Route Rate Limiting | Sliding window rate limiter per client IP per route |
|
|
26
|
-
| Service Registry | Backends self-register, deregister, and send heartbeats |
|
|
27
|
-
| Continuous Health Checks | Every 10 seconds — auto-removes and auto-recovers upstreams |
|
|
28
|
-
| HTTPS / TLS Termination | Full SSL at the proxy; all HTTP auto-redirected (301) |
|
|
29
|
-
| Sticky Sessions | Cookie-based session affinity per upstream |
|
|
30
|
-
| Retry Logic | Up to 2 retries on upstream failure, each on a different upstream |
|
|
31
|
-
| Graceful Shutdown | Drains all connections on SIGTERM / SIGINT |
|
|
32
|
-
| Hot Reload | Watches `config.yaml` and `config.d/` — zero-downtime config updates |
|
|
33
|
-
| Admin API | Live stats for load balancer, cache, registry, auto scaler |
|
|
34
|
-
| YAML Configuration | One file, fully validated with Zod — no source code changes needed |
|
|
49
|
+
## 📐 Enterprise Design Patterns Implemented
|
|
35
50
|
|
|
36
|
-
|
|
51
|
+
1. **Strategy Pattern (`ILoadBalancerStrategy`, `IRateLimiterAlgorithm`)**: Decouples algorithm selection from proxy execution. All 12 load balancing and 5 rate limiting algorithms implement common interfaces and are swapped at runtime.
|
|
52
|
+
2. **Factory Pattern (`BalancerFactory`)**: Centralized instantiator that parses Zod schemas and generates configured load balancer strategies.
|
|
53
|
+
3. **Dependency Inversion Principle (SOLID)**: Core proxy components depend strictly on abstractions (`ICache`, `IInvalidator`, `IServiceRegistry`), enabling seamless swapping between Memory, Redis, and Hybrid stores.
|
|
54
|
+
4. **Koa/Express Onion Middleware Model**: Declarative pipeline (`RequestContext`, `MiddlewarePipeline`) executing CORS, Authentication, Tracing, Rate Limiting, Cache, and Circuit Breakers in non-blocking order.
|
|
55
|
+
5. **Zero-Copy TCP Socket Tunneling**: Direct bidirectional piping (`clientSocket.pipe(targetSocket)`) for WebSocket and HTTPS connections.
|
|
37
56
|
|
|
38
|
-
|
|
57
|
+
---
|
|
39
58
|
|
|
40
|
-
|
|
59
|
+
## ⚡ Core Systems & Features
|
|
41
60
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
```
|
|
61
|
+
### 1. Advanced Load Balancing Engine (12 Strategies)
|
|
62
|
+
All load balancing strategies are dynamically validated using Zod schemas and instantiated via `BalancerFactory`:
|
|
45
63
|
|
|
46
|
-
|
|
64
|
+
* **Weighted Round-Robin (WRR)**: Smooth interleaved scheduling (NGINX style) using `currentWeight` adjustments.
|
|
65
|
+
* **Adaptive Weighted Round-Robin**: Automatically modifies weights in real time based on latency EWMA and request error rates.
|
|
66
|
+
* **Power of Two Choices (P2C)**: Pick two random healthy upstreams and route to the one with the lowest active connections ($O(1)$ efficiency).
|
|
67
|
+
* **Least Connections**: Route to the healthy upstream with the fewest active connections.
|
|
68
|
+
* **Weighted Least Connections**: Select using the `activeConnections / weight` ratio.
|
|
69
|
+
* **Least Response Time**: Route using latency EWMA (Exponentially Weighted Moving Average).
|
|
70
|
+
* **Consistent Hashing**: Distributed virtual node (150 replicas) ring mapping client IP to upstreams with minimum cache eviction.
|
|
71
|
+
* **IP Hash**: FNV-1a hash-modulo routing using client IP.
|
|
72
|
+
* **Sticky Sessions**: Cookie-based (`NINJA_ROUTE`) session affinity.
|
|
73
|
+
* **Resource-Based**: Telemetry-aware load routing using live CPU and memory metrics reported by sidecars.
|
|
74
|
+
* **Random Selection**: Fallback randomized distribution.
|
|
47
75
|
|
|
48
|
-
|
|
49
|
-
openssl req -x509 -newkey rsa:4096 \
|
|
50
|
-
-keyout key.pem -out cert.pem \
|
|
51
|
-
-days 365 -nodes \
|
|
52
|
-
-subj "/CN=localhost"
|
|
53
|
-
```
|
|
76
|
+
---
|
|
54
77
|
|
|
55
|
-
###
|
|
78
|
+
### 2. High-Performance Multi-Tier Caching & Invalidation
|
|
79
|
+
* **L1/L2 Hybrid Caching**: In-memory LRU cache (L1 RAM) backed by Redis (L2 Distributed Store) with automatic L1 warming & background synchronization.
|
|
80
|
+
* **Debezium CDC (Change Data Capture) Invalidation**: Subscribes to Redis Pub/Sub events from Debezium Server. Parses transaction log updates from SQL databases and MongoDB (supporting ObjectId `$oid` conversions) to invalidate cached paths instantly:
|
|
81
|
+
* *SQL Event Map*: `{"op":"u", "source":{"table":"orders"}, "after":{"id":999}}` $\rightarrow$ Invalidates `/api/orders/999`.
|
|
82
|
+
* *Mongo Event Map*: `{"op":"u", "source":{"collection":"orders"}, "after":{"_id":{"$oid":"60d5ec4b..."}}}` $\rightarrow$ Invalidates matching mapped paths.
|
|
83
|
+
* **Pattern & Tag-Based Invalidation**: Glob pattern matching (`PatternInvalidator`) and metadata grouping (`TagInvalidator`).
|
|
84
|
+
* **Cache Control Directives (`CacheControlParser`)**: Parses standards-compliant HTTP headers (`no-store`, `no-cache`, `max-age`, `s-maxage`, `private`).
|
|
85
|
+
* **Cache Normalization (`KeyBuilder`)**: Strips marketing query parameters (`utm_source`, `fbclid`) and handles `Vary` headers (`Accept-Encoding: gzip`).
|
|
86
|
+
* **Advanced Cache Policies**:
|
|
87
|
+
* `stale-while-revalidate`: Serves stale cache while triggering concurrent lock-free background revalidation (preventing Thundering Herd / Cache Stampedes).
|
|
88
|
+
* `stale-if-error`: Serves expired stale cache during upstream 5xx or network outages.
|
|
56
89
|
|
|
57
|
-
|
|
58
|
-
# config.yaml
|
|
59
|
-
server:
|
|
60
|
-
listen: 8080
|
|
61
|
-
httpsPort: 8443
|
|
62
|
-
workers: 2
|
|
90
|
+
---
|
|
63
91
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
maxAttempts: 2
|
|
70
|
-
statusCodes: [502, 503, 504]
|
|
71
|
-
|
|
72
|
-
upstreams:
|
|
73
|
-
- id: my-api
|
|
74
|
-
url: http://localhost:5000
|
|
75
|
-
- id: my-api-2
|
|
76
|
-
url: http://localhost:5001
|
|
77
|
-
|
|
78
|
-
paths:
|
|
79
|
-
- path: /
|
|
80
|
-
upstream: [my-api, my-api-2]
|
|
81
|
-
|
|
82
|
-
headers:
|
|
83
|
-
- key: X-Forwarded-For
|
|
84
|
-
value: client_ip
|
|
85
|
-
|
|
86
|
-
cache:
|
|
87
|
-
enabled: false
|
|
88
|
-
host: redis
|
|
89
|
-
port: 6379
|
|
90
|
-
ttlSeconds: 60
|
|
91
|
-
```
|
|
92
|
+
### 3. Distributed Rate Limiting & Throttling
|
|
93
|
+
* **5 Algorithms**: `token-bucket`, `leaking-bucket`, `fixed-window`, `sliding-window-log`, and `sliding-window-counter`.
|
|
94
|
+
* **Atomic Redis Lua Scripts**: Server-side Lua script execution preventing race conditions across distributed proxy nodes.
|
|
95
|
+
* **Soft Limit Warning & Burst Policy**: Dynamically increases burst limit ($1.5\times$ base limit) when current system load is below soft threshold.
|
|
96
|
+
* **Multi-Dimension Rules**: Independent rate limiting rules evaluated per IP, Route, API-Key, and Header combination (`rl:ip:/api/v1:10.0.0.1`).
|
|
92
97
|
|
|
93
|
-
|
|
98
|
+
---
|
|
94
99
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
100
|
+
### 4. Advanced Fault Tolerance & Resilience
|
|
101
|
+
* **Classic Circuit Breaker**: Standard state machine (`CLOSED` $\rightarrow$ `OPEN` $\rightarrow$ `HALF_OPEN`) based on consecutive failure thresholds.
|
|
102
|
+
* **Google SRE EWMA Adaptive Circuit Breaker**: Rate-based shedding model using Google SRE probability math:
|
|
103
|
+
$$P = \frac{\text{requests} - K \times \text{accepts}}{\text{requests} + 1}$$
|
|
104
|
+
* **Bulkhead Pattern**: Concurrency isolation slots preventing slow upstreams from exhausting worker thread pools.
|
|
105
|
+
* **4 Jitter Backoff Algorithms**:
|
|
106
|
+
* `ExponentialBackoff`: Deterministic doubling.
|
|
107
|
+
* `FullJitterBackoff`: $Random(0, min(cap, base \times 2^{attempt}))$.
|
|
108
|
+
* `EqualJitterBackoff`: $\frac{temp}{2} + Random(0, \frac{temp}{2})$.
|
|
109
|
+
* `DecorrelatedJitterBackoff`: $Random(base, previousSleep \times 3)$.
|
|
110
|
+
* **Retry Budgets**: Capped retry allowance (e.g. max 15% retry budget) to prevent upstream retry storms.
|
|
98
111
|
|
|
99
|
-
|
|
112
|
+
---
|
|
100
113
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
114
|
+
### 5. Dynamic Service Registry & Health Probes
|
|
115
|
+
* **Dynamic Self-Registration REST API**: Upstreams can self-register, heartbeat, and deregister (`/__registry/register`, `heartbeat`, `deregister`).
|
|
116
|
+
* **Disk Snapshot Persistence**: Automatic rehydration of services from `registry.json` snapshot backups on proxy restart.
|
|
117
|
+
* **Dual Health Probes**: Active HTTP ping probes (`checkUpstream`) + Passive background failure monitors.
|
|
105
118
|
|
|
106
119
|
---
|
|
107
120
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
121
|
+
### 6. Observability, Telemetry & Multi-Tenant Logging
|
|
122
|
+
* **Prometheus Exposition Endpoint (`/metrics`)**: Exposes latency percentiles (P50, P95, P99), RPS, active connections, and circuit breaker status.
|
|
123
|
+
* **5 Auto-Provisioned Grafana Dashboards**: Visual monitoring dashboards for Proxy Overview, Load Balancers, Cache, Circuit Breakers, and Rate Limiters.
|
|
124
|
+
* **Tenant Log Streamer**: Webhook log streaming engine dispatching structured JSON access logs to tenant HTTP webhooks.
|
|
111
125
|
|
|
112
|
-
|
|
113
|
-
# Register a new upstream dynamically
|
|
114
|
-
curl -X POST -H "Content-Type: application/json" \
|
|
115
|
-
-d '{"id":"my-service","url":"http://localhost:3000"}' \
|
|
116
|
-
http://localhost:8080/__registry/register
|
|
126
|
+
---
|
|
117
127
|
|
|
118
|
-
|
|
119
|
-
curl -X PUT http://localhost:8080/__registry/heartbeat/my-service
|
|
128
|
+
## 📄 Complete Production `config.yaml` Reference
|
|
120
129
|
|
|
121
|
-
|
|
122
|
-
|
|
130
|
+
```yaml
|
|
131
|
+
server:
|
|
132
|
+
host: "0.0.0.0"
|
|
133
|
+
port: 8080
|
|
134
|
+
httpsPort: 8443
|
|
135
|
+
workers: 4
|
|
136
|
+
|
|
137
|
+
upstreams:
|
|
138
|
+
- id: "app-node-1"
|
|
139
|
+
url: "http://127.0.0.1:3000"
|
|
140
|
+
weight: 3
|
|
141
|
+
maxConnections: 500
|
|
142
|
+
healthPath: "/health"
|
|
143
|
+
- id: "app-node-2"
|
|
144
|
+
url: "http://127.0.0.1:3001"
|
|
145
|
+
weight: 1
|
|
146
|
+
maxConnections: 500
|
|
147
|
+
healthPath: "/health"
|
|
148
|
+
|
|
149
|
+
loadBalancing:
|
|
150
|
+
strategy: "weighted-round-robin" # Options: round-robin, least-connections, power-of-two, consistent-hashing, adaptive-wrr, resource-based
|
|
151
|
+
stickyCookieName: "NINJA_ROUTE"
|
|
152
|
+
|
|
153
|
+
rateLimit:
|
|
154
|
+
enabled: true
|
|
155
|
+
storage: "memory" # Options: memory, redis, hybrid
|
|
156
|
+
algorithm: "token-bucket" # Options: fixed-window, sliding-window-log, sliding-window-counter, token-bucket, leaking-bucket
|
|
157
|
+
windowMs: 60000
|
|
158
|
+
maxRequests: 1000
|
|
159
|
+
softLimit: true
|
|
160
|
+
dimensions:
|
|
161
|
+
- dimension: "ip"
|
|
162
|
+
maxRequests: 100
|
|
163
|
+
windowMs: 60000
|
|
164
|
+
- dimension: "api-key"
|
|
165
|
+
maxRequests: 500
|
|
166
|
+
windowMs: 60000
|
|
167
|
+
|
|
168
|
+
cache:
|
|
169
|
+
enabled: true
|
|
170
|
+
ttlSeconds: 60
|
|
171
|
+
l1MaxSize: 1000
|
|
172
|
+
staleWhileRevalidate: true
|
|
173
|
+
staleIfError: true
|
|
174
|
+
debezium:
|
|
175
|
+
enabled: true
|
|
176
|
+
channel: "debezium-cdc-events"
|
|
177
|
+
mappings:
|
|
178
|
+
- table: "orders"
|
|
179
|
+
pathPattern: "/api/orders/{id}"
|
|
180
|
+
|
|
181
|
+
resilience:
|
|
182
|
+
circuitBreaker:
|
|
183
|
+
mode: "adaptive" # Options: classic, adaptive
|
|
184
|
+
failureThreshold: 3
|
|
185
|
+
recoveryTimeMs: 10000
|
|
186
|
+
bulkhead:
|
|
187
|
+
maxConcurrent: 100
|
|
188
|
+
retry:
|
|
189
|
+
maxAttempts: 3
|
|
190
|
+
backoff: "full-jitter" # Options: exponential, full-jitter, equal-jitter, decorrelated-jitter
|
|
191
|
+
|
|
192
|
+
observability:
|
|
193
|
+
metrics:
|
|
194
|
+
enabled: true
|
|
195
|
+
path: "/metrics"
|
|
123
196
|
```
|
|
124
197
|
|
|
125
198
|
---
|
|
126
199
|
|
|
127
|
-
##
|
|
128
|
-
|
|
129
|
-
Drop extra config files into a `config.d/` folder — the proxy merges them automatically with zero downtime:
|
|
200
|
+
## 🧪 Testing & Verification Suites
|
|
130
201
|
|
|
202
|
+
### 1. Run Complete 63-Unit & Integration Test Suite
|
|
131
203
|
```bash
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
# Each tenant/app gets their own isolated file
|
|
135
|
-
echo "
|
|
136
|
-
server:
|
|
137
|
-
upstreams:
|
|
138
|
-
- id: tenant-a
|
|
139
|
-
url: http://localhost:4000
|
|
140
|
-
paths:
|
|
141
|
-
- path: /tenant-a
|
|
142
|
-
upstream: [tenant-a]
|
|
143
|
-
" > config.d/tenant-a.yaml
|
|
204
|
+
node node_modules/typescript/bin/tsc -p tsconfig.test.json && node --test dist-test/tests/unit/**/*.js dist-test/tests/integration/*.js
|
|
144
205
|
```
|
|
145
206
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
207
|
+
### 2. Run 30-Feature Audit & Report Generator
|
|
208
|
+
```bash
|
|
209
|
+
node node_modules/typescript/bin/tsc -p tsconfig.test.json && node dist-test/scripts/verify-all-features.js
|
|
210
|
+
```
|
|
211
|
+
*(Generates markdown proof report in `results/interview_proof_report.md`)*
|
|
151
212
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
| `/__registry` | GET | All registered services |
|
|
157
|
-
| `/__registry/register` | POST | Register a new upstream |
|
|
158
|
-
| `/__registry/deregister/:id` | DELETE | Deregister an upstream |
|
|
159
|
-
| `/__registry/heartbeat/:id` | PUT | Upstream heartbeat ping |
|
|
213
|
+
### 3. Run Production High-RPS Benchmark
|
|
214
|
+
```bash
|
|
215
|
+
npx tsx scripts/benchmark.ts https://localhost:8443/ 1000 20
|
|
216
|
+
```
|
|
160
217
|
|
|
161
218
|
---
|
|
162
219
|
|
|
163
|
-
##
|
|
220
|
+
## 📦 Build & NPM Publish
|
|
164
221
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
| `server.httpsPort` | `8443` | HTTPS port — main entry point |
|
|
169
|
-
| `server.workers` | `2` | Set to your CPU core count |
|
|
170
|
-
| `loadBalancing.strategy` | `round-robin` | `round-robin` \| `least-connections` \| `ip-hash` \| `random` |
|
|
171
|
-
| `loadBalancing.failure0Threshold` | `3` | Mark upstream DOWN after N consecutive failures |
|
|
172
|
-
| `loadBalancing.recoveryTimeMs` | `15000` | Retry a DOWN upstream after N ms |
|
|
173
|
-
| `cache.enabled` | `false` | Enable Redis GET response caching |
|
|
174
|
-
| `cache.ttlSeconds` | `60` | Cache TTL in seconds |
|
|
175
|
-
|
|
176
|
-
---
|
|
177
|
-
|
|
178
|
-
## Repository
|
|
222
|
+
```bash
|
|
223
|
+
# Build TypeScript bundle to dist/
|
|
224
|
+
pnpm run build
|
|
179
225
|
|
|
180
|
-
|
|
226
|
+
# Publish to npmjs.com
|
|
227
|
+
npm publish
|
|
228
|
+
```
|
|
181
229
|
|
|
182
230
|
---
|
|
183
231
|
|
|
184
|
-
## License
|
|
232
|
+
## 📜 License
|
|
185
233
|
|
|
186
|
-
MIT
|
|
234
|
+
MIT License © 2026 Praveen Kumar
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface IBalancer {
|
|
2
|
+
pickFiltered(healthyIds: Set<string>, clientIp?: string, attemptedIds?: Set<string>, cookies?: string): string | null;
|
|
3
|
+
recordSuccess(id: string, latencyMs?: number): void;
|
|
4
|
+
recordFailure(id: string): void;
|
|
5
|
+
setHealthy(id: string, healthy: boolean): void;
|
|
6
|
+
getStats(): Record<string, any>;
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=balancer.interface.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"balancer.interface.d.ts","sourceRoot":"","sources":["../../../src/balancer/contracts/balancer.interface.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,SAAS;IACxB,YAAY,CACV,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,EACvB,QAAQ,CAAC,EAAE,MAAM,EACjB,YAAY,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,EAC1B,OAAO,CAAC,EAAE,MAAM,GACf,MAAM,GAAG,IAAI,CAAC;IACjB,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpD,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IAC/C,QAAQ,IAAI,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CACjC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"balancer.interface.js","sourceRoot":"","sources":["../../../src/balancer/contracts/balancer.interface.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.types.d.ts","sourceRoot":"","sources":["../../../src/balancer/contracts/context.types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.types.js","sourceRoot":"","sources":["../../../src/balancer/contracts/context.types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { UpstreamState } from "../../types/upstream.types.js";
|
|
2
|
+
export interface IStrategy {
|
|
3
|
+
pick(candidates: UpstreamState[], clientIp?: string, cookies?: string): UpstreamState | null;
|
|
4
|
+
onUpstreamsChanged?(upstreams: UpstreamState[]): void;
|
|
5
|
+
}
|
|
6
|
+
//# sourceMappingURL=strategy.interface.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"strategy.interface.d.ts","sourceRoot":"","sources":["../../../src/balancer/contracts/strategy.interface.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAEnE,MAAM,WAAW,SAAS;IACxB,IAAI,CACF,UAAU,EAAE,aAAa,EAAE,EAC3B,QAAQ,CAAC,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,MAAM,GACf,aAAa,GAAG,IAAI,CAAC;IACxB,kBAAkB,CAAC,CAAC,SAAS,EAAE,aAAa,EAAE,GAAG,IAAI,CAAC;CACvD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"strategy.interface.js","sourceRoot":"","sources":["../../../src/balancer/contracts/strategy.interface.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { LoadBalancerOptions } from "../../types/balancer.types.js";
|
|
2
|
+
import type { IStrategy } from "../contracts/strategy.interface.js";
|
|
3
|
+
export declare class LoadBalancer {
|
|
4
|
+
private strategy;
|
|
5
|
+
private ewmaAlpha;
|
|
6
|
+
private slowStartSeconds;
|
|
7
|
+
private circuitBreakerConfig;
|
|
8
|
+
private states;
|
|
9
|
+
constructor(options: LoadBalancerOptions, strategy: IStrategy);
|
|
10
|
+
addUpstream(id: string, url: string, weight?: number, maxConnections?: number): void;
|
|
11
|
+
removeUpstream(id: string): void;
|
|
12
|
+
setHealthy(id: string, healthy: boolean): void;
|
|
13
|
+
incrementConnection(id: string): void;
|
|
14
|
+
releaseConnection(id: string): void;
|
|
15
|
+
recordSuccess(id: string, latencyMs?: number): void;
|
|
16
|
+
recordFailure(id: string): void;
|
|
17
|
+
pickFiltered(healthyIds: Set<string>, clientIp?: string, attemptedIds?: Set<string>, cookies?: string): string | null;
|
|
18
|
+
getStats(): any[];
|
|
19
|
+
private notifyStrategy;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=load-balancer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"load-balancer.d.ts","sourceRoot":"","sources":["../../../src/balancer/core/load-balancer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AAMzE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oCAAoC,CAAC;AAEpE,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAY;IAC5B,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,gBAAgB,CAAS;IACjC,OAAO,CAAC,oBAAoB,CAAM;IAClC,OAAO,CAAC,MAAM,CAAoC;gBAEtC,OAAO,EAAE,mBAAmB,EAAE,QAAQ,EAAE,SAAS;IAoCtD,WAAW,CAChB,EAAE,EAAE,MAAM,EACV,GAAG,EAAE,MAAM,EACX,MAAM,SAAI,EACV,cAAc,CAAC,EAAE,MAAM;IA2BlB,cAAc,CAAC,EAAE,EAAE,MAAM;IAKzB,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO;IAyBvC,mBAAmB,CAAC,EAAE,EAAE,MAAM;IAI9B,iBAAiB,CAAC,EAAE,EAAE,MAAM;IAI5B,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,SAAI;IAuCvC,aAAa,CAAC,EAAE,EAAE,MAAM;IAsBxB,YAAY,CACjB,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,EACvB,QAAQ,CAAC,EAAE,MAAM,EACjB,YAAY,cAAoB,EAChC,OAAO,CAAC,EAAE,MAAM,GACf,MAAM,GAAG,IAAI;IAqCT,QAAQ,IAAI,GAAG,EAAE;IAsBxB,OAAO,CAAC,cAAc;CAKvB"}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { logger } from "../../observability/logger/logger.js";
|
|
2
|
+
import { circuitBreakerManager } from "../../resilience/circuit-breaker/circuit-breaker.manager.js";
|
|
3
|
+
import { ClassicCircuitBreaker } from "../../resilience/circuit-breaker/classic.circuit-breaker.js";
|
|
4
|
+
import { AdaptiveCircuitBreaker } from "../../resilience/circuit-breaker/adaptive.circuit-breaker.js";
|
|
5
|
+
export class LoadBalancer {
|
|
6
|
+
strategy;
|
|
7
|
+
ewmaAlpha;
|
|
8
|
+
slowStartSeconds;
|
|
9
|
+
circuitBreakerConfig;
|
|
10
|
+
states = new Map();
|
|
11
|
+
constructor(options, strategy) {
|
|
12
|
+
this.strategy = strategy;
|
|
13
|
+
this.ewmaAlpha = options.ewmaAlpha ?? 0.1;
|
|
14
|
+
this.slowStartSeconds = options.slowStartSeconds ?? 30;
|
|
15
|
+
this.circuitBreakerConfig = options.circuitBreaker ?? {
|
|
16
|
+
mode: "classic",
|
|
17
|
+
failureThreshold: options.failureThreshold ?? 3,
|
|
18
|
+
recoveryTimeMs: options.recoveryTimeMs ?? 15000,
|
|
19
|
+
K: 2,
|
|
20
|
+
windowMs: 10000,
|
|
21
|
+
};
|
|
22
|
+
for (const upstream of options.upstreams) {
|
|
23
|
+
this.states.set(upstream.id, {
|
|
24
|
+
id: upstream.id,
|
|
25
|
+
weight: upstream.weight ?? 1,
|
|
26
|
+
activeConnections: 0,
|
|
27
|
+
failures: 0,
|
|
28
|
+
state: "CLOSED",
|
|
29
|
+
lastFailureTime: 0,
|
|
30
|
+
responseTime: 10,
|
|
31
|
+
healthy: true,
|
|
32
|
+
requests: 0,
|
|
33
|
+
accepts: 0,
|
|
34
|
+
slowStartEndTime: 0,
|
|
35
|
+
maxConnections: upstream.maxConnections,
|
|
36
|
+
currentWeight: 0,
|
|
37
|
+
});
|
|
38
|
+
circuitBreakerManager.getOrCreate(upstream.id, this.circuitBreakerConfig.mode, this.circuitBreakerConfig);
|
|
39
|
+
}
|
|
40
|
+
this.notifyStrategy();
|
|
41
|
+
}
|
|
42
|
+
addUpstream(id, url, weight = 1, maxConnections) {
|
|
43
|
+
if (this.states.has(id))
|
|
44
|
+
return;
|
|
45
|
+
this.states.set(id, {
|
|
46
|
+
id,
|
|
47
|
+
url,
|
|
48
|
+
activeConnections: 0,
|
|
49
|
+
failures: 0,
|
|
50
|
+
lastFailureTime: 0,
|
|
51
|
+
state: "CLOSED",
|
|
52
|
+
healthy: true,
|
|
53
|
+
weight,
|
|
54
|
+
responseTime: 10,
|
|
55
|
+
totalBytes: 0,
|
|
56
|
+
requests: 0,
|
|
57
|
+
accepts: 0,
|
|
58
|
+
slowStartEndTime: 0,
|
|
59
|
+
maxConnections,
|
|
60
|
+
currentWeight: 0,
|
|
61
|
+
});
|
|
62
|
+
circuitBreakerManager.getOrCreate(id, this.circuitBreakerConfig.mode, this.circuitBreakerConfig);
|
|
63
|
+
this.notifyStrategy();
|
|
64
|
+
}
|
|
65
|
+
removeUpstream(id) {
|
|
66
|
+
if (this.states.delete(id)) {
|
|
67
|
+
this.notifyStrategy();
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
setHealthy(id, healthy) {
|
|
71
|
+
const s = this.states.get(id);
|
|
72
|
+
if (!s)
|
|
73
|
+
return;
|
|
74
|
+
if (s.healthy !== healthy) {
|
|
75
|
+
logger.info("LoadBalancer", `Upstream health changed: ${id} -> ${healthy ? "HEALTHY" : "UNHEALTHY"}`);
|
|
76
|
+
s.healthy = healthy;
|
|
77
|
+
if (healthy) {
|
|
78
|
+
const cb = circuitBreakerManager.getOrCreate(id, this.circuitBreakerConfig.mode, this.circuitBreakerConfig);
|
|
79
|
+
if (cb instanceof ClassicCircuitBreaker &&
|
|
80
|
+
cb.getState() === "OPEN") {
|
|
81
|
+
cb.recordSuccess(0);
|
|
82
|
+
}
|
|
83
|
+
s.slowStartEndTime = Date.now() + this.slowStartSeconds * 1000;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
incrementConnection(id) {
|
|
88
|
+
const s = this.states.get(id);
|
|
89
|
+
if (s)
|
|
90
|
+
s.activeConnections++;
|
|
91
|
+
}
|
|
92
|
+
releaseConnection(id) {
|
|
93
|
+
const s = this.states.get(id);
|
|
94
|
+
if (s && s.activeConnections > 0)
|
|
95
|
+
s.activeConnections--;
|
|
96
|
+
}
|
|
97
|
+
recordSuccess(id, latencyMs = 0) {
|
|
98
|
+
const s = this.states.get(id);
|
|
99
|
+
if (!s)
|
|
100
|
+
return;
|
|
101
|
+
s.responseTime =
|
|
102
|
+
this.ewmaAlpha * latencyMs + (1 - this.ewmaAlpha) * s.responseTime;
|
|
103
|
+
const cb = circuitBreakerManager.getOrCreate(id, this.circuitBreakerConfig.mode, this.circuitBreakerConfig);
|
|
104
|
+
const prevState = cb instanceof ClassicCircuitBreaker ? cb.getState() : "CLOSED";
|
|
105
|
+
cb.recordSuccess(latencyMs);
|
|
106
|
+
const postState = cb instanceof ClassicCircuitBreaker ? cb.getState() : "CLOSED";
|
|
107
|
+
if (cb instanceof ClassicCircuitBreaker &&
|
|
108
|
+
(prevState === "OPEN" || prevState === "HALF_OPEN") &&
|
|
109
|
+
postState === "CLOSED") {
|
|
110
|
+
logger.info("CircuitBreaker", `${id} restored to CLOSED state`);
|
|
111
|
+
s.slowStartEndTime = 0;
|
|
112
|
+
let totalWeight = 0;
|
|
113
|
+
for (const [, state] of this.states) {
|
|
114
|
+
const peerCb = circuitBreakerManager.getOrCreate(state.id, this.circuitBreakerConfig.mode, this.circuitBreakerConfig);
|
|
115
|
+
const peerOpen = peerCb instanceof ClassicCircuitBreaker &&
|
|
116
|
+
peerCb.getState() === "OPEN";
|
|
117
|
+
if (state.healthy && !peerOpen) {
|
|
118
|
+
totalWeight += state.weight;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
s.currentWeight -= totalWeight;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
recordFailure(id) {
|
|
125
|
+
const s = this.states.get(id);
|
|
126
|
+
if (!s)
|
|
127
|
+
return;
|
|
128
|
+
const cb = circuitBreakerManager.getOrCreate(id, this.circuitBreakerConfig.mode, this.circuitBreakerConfig);
|
|
129
|
+
const prevState = cb instanceof ClassicCircuitBreaker ? cb.getState() : "CLOSED";
|
|
130
|
+
cb.recordFailure();
|
|
131
|
+
const postState = cb instanceof ClassicCircuitBreaker ? cb.getState() : "CLOSED";
|
|
132
|
+
if (cb instanceof ClassicCircuitBreaker &&
|
|
133
|
+
prevState !== "OPEN" &&
|
|
134
|
+
postState === "OPEN") {
|
|
135
|
+
logger.warn("CircuitBreaker", `${id} tripped to OPEN state`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
pickFiltered(healthyIds, clientIp, attemptedIds = new Set(), cookies) {
|
|
139
|
+
const candidates = [];
|
|
140
|
+
for (const [id, s] of this.states.entries()) {
|
|
141
|
+
if (!healthyIds.has(id) || !s.healthy)
|
|
142
|
+
continue;
|
|
143
|
+
if (attemptedIds.has(id))
|
|
144
|
+
continue;
|
|
145
|
+
const cb = circuitBreakerManager.getOrCreate(id, this.circuitBreakerConfig.mode, this.circuitBreakerConfig);
|
|
146
|
+
if (!cb.isAllowed())
|
|
147
|
+
continue;
|
|
148
|
+
if (s.maxConnections !== undefined &&
|
|
149
|
+
s.activeConnections >= s.maxConnections) {
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
candidates.push(s);
|
|
153
|
+
}
|
|
154
|
+
if (candidates.length === 0)
|
|
155
|
+
return null;
|
|
156
|
+
const halfOpenCandidates = candidates.filter((s) => {
|
|
157
|
+
const cb = circuitBreakerManager.getOrCreate(s.id, this.circuitBreakerConfig.mode, this.circuitBreakerConfig);
|
|
158
|
+
return (cb instanceof ClassicCircuitBreaker && cb.getState() === "HALF_OPEN");
|
|
159
|
+
});
|
|
160
|
+
if (halfOpenCandidates.length > 0) {
|
|
161
|
+
return halfOpenCandidates[0].id;
|
|
162
|
+
}
|
|
163
|
+
const chosen = this.strategy.pick(candidates, clientIp, cookies);
|
|
164
|
+
return chosen ? chosen.id : null;
|
|
165
|
+
}
|
|
166
|
+
getStats() {
|
|
167
|
+
const list = [];
|
|
168
|
+
for (const [id, s] of this.states.entries()) {
|
|
169
|
+
const cb = circuitBreakerManager.getOrCreate(id, this.circuitBreakerConfig.mode, this.circuitBreakerConfig);
|
|
170
|
+
list.push({
|
|
171
|
+
id,
|
|
172
|
+
activeConnections: s.activeConnections,
|
|
173
|
+
failures: cb instanceof ClassicCircuitBreaker ? cb.getFailures() : 0,
|
|
174
|
+
state: cb instanceof ClassicCircuitBreaker ? cb.getState() : "CLOSED",
|
|
175
|
+
responseTime: s.responseTime,
|
|
176
|
+
healthy: s.healthy,
|
|
177
|
+
...(cb instanceof AdaptiveCircuitBreaker ? { adaptiveStats: cb.getStats() } : {}),
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
return list;
|
|
181
|
+
}
|
|
182
|
+
notifyStrategy() {
|
|
183
|
+
if (this.strategy.onUpstreamsChanged) {
|
|
184
|
+
this.strategy.onUpstreamsChanged([...this.states.values()]);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
//# sourceMappingURL=load-balancer.js.map
|