file-routing-expressjs
Version:
A dependency-free, flexible, system-based file routing for Express.
1 lines • 4.96 kB
Source Map (JSON)
{"version":3,"sources":["../../src/plugins/circuit-breaker.ts"],"sourcesContent":["import { isDefined, isFunction, isNotDefined } from \"../helpers/validators\";\nimport { CircutBreakerConfig, CircuteBreakerEntryState, Plugin } from \"../types\";\n\nconst STATE = new Map<string, CircuteBreakerEntryState>();\nconst ID_SYMBOL = Symbol(\"id\");\nconst KEY_SYMBOL = Symbol(\"key\");\n\nconst circuitBreakerPlugin: Plugin<CircutBreakerConfig> = {\n name: \"circuit-breaker\",\n\n validateConfig(config) {\n if (!config || typeof config.threshold !== \"number\" || config.threshold <= 0) {\n throw new Error(`[circuit-breaker] \"threshold\" must be > 0`);\n }\n\n if (typeof config.cooldown !== \"number\" || config.cooldown <= 0) {\n throw new Error(`[circuit-breaker] \"cooldown\" must be > 0`);\n }\n\n if(isDefined(config.considerError) && !isFunction(config.considerError)) {\n throw new Error(`[circuit-breaker] \"considerError\" must be a function`);\n }\n },\n\n async onRequest(ctx, next) {\n const config = ctx.config;\n if (isNotDefined(config)) return next();\n\n const key = `${ctx.req.method}:${ctx.req.route?.path || ctx.req.path}`;\n const now = Date.now();\n\n let state = STATE.get(key);\n if (isNotDefined(state)) {\n state = { failures: 0, openUntil: 0, halfOpen: false, inFlight: false };\n STATE.set(key, state);\n }\n\n ctx.state[ID_SYMBOL] = { failureCounted: false };\n ctx.state[KEY_SYMBOL] = key;\n\n if (state.openUntil > now) {\n ctx.res.status(503).send(\"Service unavailable (circuit open)\");\n return;\n }\n\n if (state.failures >= config.threshold && state.openUntil <= now) {\n if (state.inFlight) {\n ctx.res.status(503).send(\"Service unavailable (half-open busy)\");\n return;\n }\n\n state.halfOpen = true;\n state.inFlight = true;\n }\n\n try {\n await next();\n\n if (ctx.res.statusCode < 500) {\n state.failures = 0;\n state.halfOpen = false;\n }\n } finally {\n state.inFlight = false;\n }\n },\n\n async onError(err, ctx) {\n const config = ctx.config;\n if (isNotDefined(config)) return;\n\n const key = ctx.state[KEY_SYMBOL];\n\n if(isNotDefined(key)) return;\n\n const state = STATE.get(key);\n\n if (isNotDefined(state)) return;\n\n const shouldCount = isDefined(config.considerError)\n ? config.considerError(err)\n : true;\n\n if (!shouldCount) return;\n\n const meta = ctx.state[ID_SYMBOL]; \n if (!meta || meta.failureCounted) return;\n\n meta.failureCounted = true;\n state.failures++;\n\n if (state.failures >= config.threshold) {\n state.openUntil = Date.now() + config.cooldown;\n state.halfOpen = false;\n }\n }\n};\n\nexport default circuitBreakerPlugin;"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA,SAAS,WAAW,YAAY,oBAAoB;AAGpD,MAAM,QAAQ,oBAAI,IAAsC;AACxD,MAAM,YAAY,OAAO,IAAI;AAC7B,MAAM,aAAa,OAAO,KAAK;AAE/B,MAAM,uBAAoD;AAAA,EACtD,MAAM;AAAA,EAEN,eAAe,QAAQ;AACnB,QAAI,CAAC,UAAU,OAAO,OAAO,cAAc,YAAY,OAAO,aAAa,GAAG;AAC1E,YAAM,IAAI,MAAM,2CAA2C;AAAA,IAC/D;AAEA,QAAI,OAAO,OAAO,aAAa,YAAY,OAAO,YAAY,GAAG;AAC7D,YAAM,IAAI,MAAM,0CAA0C;AAAA,IAC9D;AAEA,QAAG,UAAU,OAAO,aAAa,KAAK,CAAC,WAAW,OAAO,aAAa,GAAG;AACrE,YAAM,IAAI,MAAM,sDAAsD;AAAA,IAC1E;AAAA,EACJ;AAAA,EAEM,UAAU,KAAK,MAAM;AAAA;AAxB/B;AAyBQ,YAAM,SAAS,IAAI;AACnB,UAAI,aAAa,MAAM,EAAG,QAAO,KAAK;AAEtC,YAAM,MAAM,GAAG,IAAI,IAAI,MAAM,MAAI,SAAI,IAAI,UAAR,mBAAe,SAAQ,IAAI,IAAI,IAAI;AACpE,YAAM,MAAM,KAAK,IAAI;AAErB,UAAI,QAAQ,MAAM,IAAI,GAAG;AACzB,UAAI,aAAa,KAAK,GAAG;AACrB,gBAAQ,EAAE,UAAU,GAAG,WAAW,GAAG,UAAU,OAAO,UAAU,MAAM;AACtE,cAAM,IAAI,KAAK,KAAK;AAAA,MACxB;AAEA,UAAI,MAAM,SAAS,IAAI,EAAE,gBAAgB,MAAM;AAC/C,UAAI,MAAM,UAAU,IAAI;AAExB,UAAI,MAAM,YAAY,KAAK;AACvB,YAAI,IAAI,OAAO,GAAG,EAAE,KAAK,oCAAoC;AAC7D;AAAA,MACJ;AAEA,UAAI,MAAM,YAAY,OAAO,aAAa,MAAM,aAAa,KAAK;AAC9D,YAAI,MAAM,UAAU;AAChB,cAAI,IAAI,OAAO,GAAG,EAAE,KAAK,sCAAsC;AAC/D;AAAA,QACJ;AAEA,cAAM,WAAW;AACjB,cAAM,WAAW;AAAA,MACrB;AAEA,UAAI;AACA,cAAM,KAAK;AAEX,YAAI,IAAI,IAAI,aAAa,KAAK;AAC1B,gBAAM,WAAW;AACjB,gBAAM,WAAW;AAAA,QACrB;AAAA,MACJ,UAAE;AACE,cAAM,WAAW;AAAA,MACrB;AAAA,IACJ;AAAA;AAAA,EAEM,QAAQ,KAAK,KAAK;AAAA;AACpB,YAAM,SAAS,IAAI;AACnB,UAAI,aAAa,MAAM,EAAG;AAE1B,YAAM,MAAM,IAAI,MAAM,UAAU;AAEhC,UAAG,aAAa,GAAG,EAAG;AAEtB,YAAM,QAAQ,MAAM,IAAI,GAAG;AAE3B,UAAI,aAAa,KAAK,EAAG;AAEzB,YAAM,cAAc,UAAU,OAAO,aAAa,IAC5C,OAAO,cAAc,GAAG,IACxB;AAEN,UAAI,CAAC,YAAa;AAElB,YAAM,OAAO,IAAI,MAAM,SAAS;AAChC,UAAI,CAAC,QAAQ,KAAK,eAAgB;AAElC,WAAK,iBAAiB;AACtB,YAAM;AAEN,UAAI,MAAM,YAAY,OAAO,WAAW;AACpC,cAAM,YAAY,KAAK,IAAI,IAAI,OAAO;AACtC,cAAM,WAAW;AAAA,MACrB;AAAA,IACJ;AAAA;AACJ;AAEA,IAAO,0BAAQ;","names":[]}