Skip to content

Commit

Permalink
Working Circuit Breaker
Browse files Browse the repository at this point in the history
  • Loading branch information
Arpit Adlakha authored and Arpit Adlakha committed Nov 30, 2023
1 parent 816b3a4 commit c28a387
Show file tree
Hide file tree
Showing 6 changed files with 1,418 additions and 1,890 deletions.
5 changes: 0 additions & 5 deletions dist/http/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ declare class HTTPCommunication {
axiosConfig?: AxiosRequestConfig;
contextStorage?: AsyncLocalStorage<any>;
errorHandler?: RequestErrorHandler;
private fallbackFunction;
private circuitBreaker;
/**
* HTTPCommunication to communicate with another service
Expand All @@ -67,10 +66,6 @@ declare class HTTPCommunication {
* handleError handles all errors
*/
private handleError;
/**
* createRequestURL creates a url given query parameters
*/
createRequestURL(url: string, query?: string | Record<string, string> | string[][] | URLSearchParams): string;
/**
* populateHeadersFromContext takes context provided from AsyncLocalStorage, and populates relevant headers
*/
Expand Down
34 changes: 17 additions & 17 deletions dist/http/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,15 @@ const HTTPCommunicationAxiosDefaultConfig = Object.assign(Object.assign({}, Obje
return status <= 504;
} });
exports.HTTPCommunicationAxiosDefaultConfig = HTTPCommunicationAxiosDefaultConfig;
/**
* createRequestURL creates a url given query parameters
*/
function createRequestURL(url, query) {
const searchParams = new URLSearchParams(query);
const finalURL = new URL(url);
finalURL.search = searchParams.toString();
return finalURL.toString();
}
/**
* HTTPCommunication wrapper
*/
Expand All @@ -63,23 +72,18 @@ class HTTPCommunication {
* HTTPCommunication to communicate with another service
*/
constructor({ name, axiosConfig, contextStorage, errorHandler, circuitBreakerConfig }) {
this.fallbackFunction = () => __awaiter(this, void 0, void 0, function* () {
// This is the fallback logic you want to execute when the circuit is open or requests fail
// For instance, return a default value or perform an alternative action
return 'Fallback response'; // You can customize this response based on your use case
});
this.name = name;
// default axios config
this.axiosConfig = HTTPCommunicationAxiosDefaultConfig;
if (axiosConfig) {
this.axiosConfig = Object.assign(Object.assign({}, this.axiosConfig), axiosConfig);
}
this.axiosClient = new axios_1.Axios(this.axiosConfig);
console.log({ client: this.axiosClient });
this.errorHandler = errorHandler;
this.contextStorage = contextStorage;
if (!(circuitBreakerConfig === null || circuitBreakerConfig === void 0 ? void 0 : circuitBreakerConfig.disable)) {
this.circuitBreaker = new opossum_1.default(this.makeRequest, Object.assign({ timeout: 5000, resetTimeout: 10000, errorThresholdPercentage: 50 }, circuitBreakerConfig));
this.circuitBreaker.fallback(this.fallbackFunction);
this.circuitBreaker = new opossum_1.default(this.makeRequest.bind(this), Object.assign({ timeout: 5000, resetTimeout: 10000, errorThresholdPercentage: 50 }, circuitBreakerConfig));
}
}
/**
Expand Down Expand Up @@ -130,15 +134,6 @@ class HTTPCommunication {
});
}
}
/**
* createRequestURL creates a url given query parameters
*/
createRequestURL(url, query) {
const searchParams = new URLSearchParams(query);
const finalURL = new URL(url);
finalURL.search = searchParams.toString();
return finalURL.toString();
}
/**
* populateHeadersFromContext takes context provided from AsyncLocalStorage, and populates relevant headers
*/
Expand All @@ -165,7 +160,8 @@ class HTTPCommunication {
var _a;
return __awaiter(this, void 0, void 0, function* () {
const { route, method, request, headers = {} } = params;
const requestURL = this.createRequestURL(route, request === null || request === void 0 ? void 0 : request.query);
console.log({ route, method, request, headers });
const requestURL = createRequestURL(route, request === null || request === void 0 ? void 0 : request.query);
const requestContext = this.contextStorage ? this.contextStorage.getStore() : null;
let finalHeaders = {};
if (requestContext) {
Expand All @@ -179,6 +175,10 @@ class HTTPCommunication {
if (request === null || request === void 0 ? void 0 : request.body) {
req['data'] = request.body;
}
console.log({ client: this.axiosClient, req });
if (!this.axiosClient) {
console.log('\n\n\n\n');
}
const response = yield this.axiosClient.request(req);
this.handleError(params, response);
return response.data;
Expand Down
48 changes: 13 additions & 35 deletions junit.xml
Original file line number Diff line number Diff line change
@@ -1,39 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<testsuites name="jest tests" tests="16" failures="0" errors="0" time="0.392">
<testsuite name="Circuit Breaker Test" errors="0" failures="0" skipped="0" timestamp="2023-11-30T04:46:12" time="0.25" tests="2">
<testcase classname="Circuit Breaker Test Circuit opens after multiple failed requests" name="Circuit Breaker Test Circuit opens after multiple failed requests" time="0.004">
</testcase>
<testcase classname="Circuit Breaker Test Circuit closes after successful request" name="Circuit Breaker Test Circuit closes after successful request" time="0">
</testcase>
</testsuite>
<testsuite name="HttpCommunication" errors="0" failures="0" skipped="0" timestamp="2023-11-30T04:46:12" time="0.08" tests="14">
<testcase classname="HttpCommunication Constructor should initialize with default values" name="HttpCommunication Constructor should initialize with default values" time="0.002">
</testcase>
<testcase classname="HttpCommunication Constructor should override axios config if provided" name="HttpCommunication Constructor should override axios config if provided" time="0.001">
</testcase>
<testcase classname="HttpCommunication getRequestContext should generate a request context from the request" name="HttpCommunication getRequestContext should generate a request context from the request" time="0.003">
</testcase>
<testcase classname="HttpCommunication getRequestContext should generate a request context even if route field is empty" name="HttpCommunication getRequestContext should generate a request context even if route field is empty" time="0.001">
</testcase>
<testcase classname="HttpCommunication generateHexString should generate a hex string of the specified size" name="HttpCommunication generateHexString should generate a hex string of the specified size" time="0.001">
</testcase>
<testcase classname="HttpCommunication handleError should throw QError if response status is &gt;= 400" name="HttpCommunication handleError should throw QError if response status is &gt;= 400" time="0.005">
</testcase>
<testcase classname="HttpCommunication handleError should throw QError with default errorType if not provided" name="HttpCommunication handleError should throw QError with default errorType if not provided" time="0">
</testcase>
<testcase classname="HttpCommunication handleError should throw QError with default message and errorType if response data is not provided" name="HttpCommunication handleError should throw QError with default message and errorType if response data is not provided" time="0">
</testcase>
<testcase classname="HttpCommunication createRequestURL should create a URL with query parameters" name="HttpCommunication createRequestURL should create a URL with query parameters" time="0">
</testcase>
<testcase classname="HttpCommunication populateHeadersFromContext should populate headers from the context" name="HttpCommunication populateHeadersFromContext should populate headers from the context" time="0">
</testcase>
<testcase classname="HttpCommunication populateHeadersFromContext should generate a traceId if not provided in the context" name="HttpCommunication populateHeadersFromContext should generate a traceId if not provided in the context" time="0.001">
</testcase>
<testcase classname="HttpCommunication makeRequest should make a GET request and return data" name="HttpCommunication makeRequest should make a GET request and return data" time="0">
</testcase>
<testcase classname="HttpCommunication makeRequest should handle errors correctly" name="HttpCommunication makeRequest should handle errors correctly" time="0">
</testcase>
<testcase classname="HttpCommunication HTTP Method Wrappers should make a POST request" name="HttpCommunication HTTP Method Wrappers should make a POST request" time="0.001">
<testsuites name="jest tests" tests="2" failures="1" errors="0" time="179.43">
<testsuite name="Circuit Breaker Test" errors="0" failures="1" skipped="1" timestamp="2023-11-30T10:44:26" time="179.345" tests="2">
<testcase classname="Circuit Breaker Test Circuit opens after multiple failed requests" name="Circuit Breaker Test Circuit opens after multiple failed requests" time="0">
<skipped/>
</testcase>
<testcase classname="Circuit Breaker Test Circuit closes after successful request" name="Circuit Breaker Test Circuit closes after successful request" time="178.842">
<failure>Error: expect(received).toBe(expected) // Object.is equality

Expected: &quot;hello&quot;
Received: undefined
at /Users/arpitadlakha/QuizizzProjects/temp/service-communication-wrapper/tests/http/CircuitBreaker.test.ts:71:27
at Generator.next (&lt;anonymous&gt;)
at fulfilled (/Users/arpitadlakha/QuizizzProjects/temp/service-communication-wrapper/tests/http/CircuitBreaker.test.ts:5:58)</failure>
</testcase>
</testsuite>
</testsuites>
Loading

0 comments on commit c28a387

Please sign in to comment.