Skip to content

Commit

Permalink
Merge pull request #15 from Marshal27/feature/Implement_Abort_Controller
Browse files Browse the repository at this point in the history
feat: Abort Controller
  • Loading branch information
Marshal27 authored Jun 14, 2023
2 parents 5152a32 + b4eebb9 commit fb85881
Show file tree
Hide file tree
Showing 7 changed files with 1,374 additions and 748 deletions.
122 changes: 87 additions & 35 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,38 +9,45 @@ If you find this work helpful please consider buying me a coffee.
<a href="https://www.buymeacoffee.com/marshal27" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/default-orange.png" alt="Buy Me A Coffee" height="41" width="174"></a>
____________________________

## Getting Started
# Getting Started

### Why to use it
## Why to use it

If this resilience pattern does not sounds familiar to you, take a look on these resources:
If this resilience pattern does not sound familiar to you, take a look on these resources:
- [Circuit breaker wikipedia](https://en.wikipedia.org/wiki/Circuit_breaker_design_pattern)
- [Circuit breaker - Martin Fowler](https://martinfowler.com/bliki/CircuitBreaker.html)
- [Release It!](https://pragprog.com/book/mnee2/release-it-second-edition)

### Install
## Install

```bash
npm i ky-circuit-breaker
```

### How to Use It
## How to Use It

The below approach will protect all of the following automagically.
- ky.get
- ky.post
- ky.put
- ky.patch
- ky.head
- ky.delete
```js
import ky from 'ky';
import { CircuitBreaker } from 'ky-circuit-breaker';

const circuitBreaker = new CircuitBreaker(ky);
// that's it, your native KyInstance functions
// are now protected with a CircuitBreaker.
// are now protected with a CircuitBreaker using the default settings.

const result = await ky.get('https://httpbin.org/get').json();
// make calls the normal way.
```

#### Promises
Let's assume you have an http call and you want to fail-fast gracefully without waiting for TCP connection timeout in
case of the service eventually is not available:
case of the service eventually is not available...you can protect that individual promise with the example below:
```js

const unprotectedPromise = () => fetch(someUrl).then(response => response.json());
Expand All @@ -57,9 +64,9 @@ const protectedPromise = circuitBreaker.protectPromise(unprotectedPromise);
protectedPromise().then(...);
```

### Exports
# Exports

### CircuitStatusFlag
## CircuitStatusFlag

Enum for circuitStatus

Expand All @@ -74,47 +81,92 @@ export enum CircuitStatusFlag {
}
```

usage:
```js

import { CircuitBreaker, CircuitStatusFlag } from 'ky-circuit-breaker';

if (this.circuitBreaker.circuitStatus === CircuitStatusFlag.OPEN) {
// do something interesting...
}
```
# Custom params

### Custom params

#### CircuitBreaker(config: CircuitBreakerConfig)
## CircuitBreaker(config: CircuitBreakerConfig)

Create a new instance of a circuit breaker. It accepts the following config options:

##### CircuitBreakerConfig: maxFailures
```json
maxFailures: number;
timeoutLimit: number;
hooks?: {
beforeRequest?: { (): void }[],
afterPromiseComplete?: { (recoveryAttempts: number, recoverySuccessful: boolean, recoveryFailed: boolean): void }[]
}
```

## CircuitBreakerConfig: `maxFailures`

Number of errors after the circuit trips to open and starts short-circuiting requests and failing-fast.

*Default Value:* 5

##### CircuitBreakerConfig: resetTimeoutInMillis
## CircuitBreakerConfig: `timeoutLimit`

Time in milliseconds in which after tripping to open the circuit will remain failing fast.

*Default Value:* 1000

##### CircuitBreakerConfig: openCircuitNoOp

Boolean value to NoOp the return of rejected promise when in a fail fast state.

*Default Value:* false
*Default Value:* 5000

##### CircuitBreakerConfig: noOpReturn
## CircuitBreakerConfig: `hooks`

Return string value for NoOp when in a fail fast state.
Hooks specific to the circuit breaker.

*Default Value:* '[{ "error" : "CircuitBreaker open circuit" }]'
`beforeRequest` - **Synonymous to ky before request hook** - function callback before every request.
`afterPromiseComplete` - function callback after every promise is complete.

## Possible Usage:
```typescript

const circuitBreaker = new CircuitBreaker({maxFailures: 10, resetTimeoutInMillis: 10000, openCircuitNoOp: true, noOpReturn: '[{"error" : "CircuitBreaker Error!"}]'});
````
import { CircuitBreaker, CircuitStatusFlag } from 'ky-circuit-breaker';

private setHttpClient(): void {
const circuitBreakerStateHandler = (recoveryAttempts?, recoveryFailed?) => {
if (this.circuitBreaker.circuitStatus === CircuitStatusFlag.OPEN && recoveryAttempts === this.circuitRecoveryThreshold) {
/* Shut down the app */
return;
}

switch (this.circuitBreaker.circuitStatus) {
case CircuitStatusFlag.CLOSED: {
/* Handle circuit breaker closure */
if (recoverySuccessful) {
/* Handle recovery successful */
}
break;
}
case CircuitStatusFlag.OPEN: {
/* Handle circuit breaker opening */
if (recoveryFailed) {
/* Handle recovery failure */
}
break;
}
case CircuitStatusFlag.HALF: {
/* Handle circuit breaker half open*/
break;
}
default:
break;
}
};

this.httpClient = ky.extend({
prefixUrl,
timeout: false,
retry: {
limit: 5,
methods: ['post', 'get', 'put']
},
});
this.circuitBreaker = new CircuitBreaker(this.httpClient, {
maxFailures: 5,
timeoutLimit: 5000,
hooks: {
beforeRequest: [circuitBreakerStateHandler],
afterPromiseComplete: [circuitBreakerStateHandler]
}
});
}
}
```
2 changes: 1 addition & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/** @type {import('ts-jest').JestConfigWithTsJest} */
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
testEnvironment: 'jsdom',
};
Loading

0 comments on commit fb85881

Please sign in to comment.