Skip to main content

Configuring CircuitBreaker adapters

RedisCircuitBreakerAdapter​

To use the RedisCircuitBreakerAdapter, you'll need to:

  1. Install the required dependency: ioredis package.

Setup​

Connect to Redis:

./samples/redis-circuit-breaker-adapter-setup.ts
import { Redis } from "ioredis";

export const database = new Redis("YOUR_REDIS_CONNECTION_STRING");

Usage​

Create the adapter:

./samples/redis-circuit-breaker-adapter.ts
import { RedisCircuitBreakerAdapter } from "eridu-tech/circuit-breaker/redis-circuit-breaker-adapter";
import { database } from "./redis-circuit-breaker-adapter-setup.js";

const redisCircuitBreakerAdapter = new RedisCircuitBreakerAdapter({
database,
});

Configuring backoff policy​

The type field is the only required field. All other fields are optional.

./samples/redis-circuit-breaker-backoff-policy.ts
import { BACKOFFS } from "eridu-tech/backoff-policies";
import { RedisCircuitBreakerAdapter } from "eridu-tech/circuit-breaker/redis-circuit-breaker-adapter";
import { Redis } from "ioredis";
import { TimeSpan } from "eridu-tech/time-span";

const database = new Redis("YOUR_REDIS_CONNECTION_STRING");
const redisCircuitBreakerAdapter = new RedisCircuitBreakerAdapter({
database,
backoffPolicy: {
type: BACKOFFS.CONSTANT,
delay: TimeSpan.fromSeconds(1),
jitter: 0.5,
},
});

The settings are the same as backoff policies settings.

Configuring CircuitBreaker policy​

The type field is the only required field. All other fields are optional.

./samples/redis-circuit-breaker-policy.ts
import { BREAKER_POLICIES } from "eridu-tech/circuit-breaker/policies";
import { RedisCircuitBreakerAdapter } from "eridu-tech/circuit-breaker/redis-circuit-breaker-adapter";
import { Redis } from "ioredis";

const database = new Redis("YOUR_REDIS_CONNECTION_STRING");
const redisCircuitBreakerAdapter = new RedisCircuitBreakerAdapter({
database,
circuitBreakerPolicy: {
type: BREAKER_POLICIES.CONSECUTIVE,
failureThreshold: 5,
successThreshold: 5,
},
});

The settings are the same as circuit-breaker policies settings.

DatabaseCircuitBreakerAdapter​

To use the DatabaseCircuitBreakerAdapter, you'll need to use ICircuitBreakerStorageAdapter:

  1. Creating ICircuitBreakerStorageAdapter:
./samples/circuit-breaker-storage-adapter.ts
import { MemoryCircuitBreakerStorageAdapter } from "eridu-tech/circuit-breaker/memory-circuit-breaker-storage-adapter";

export const circuitBreakerStorageAdapter =
new MemoryCircuitBreakerStorageAdapter();
  1. Creating DatabaseCircuitBreakerAdapter:
./samples/database-circuit-breaker-adapter.ts
import { DatabaseCircuitBreakerAdapter } from "eridu-tech/circuit-breaker/database-circuit-breaker-adapter";
import { circuitBreakerStorageAdapter } from "./circuit-breaker-storage-adapter.js";

const circuitBreakerAdapter = new DatabaseCircuitBreakerAdapter({
adapter: circuitBreakerStorageAdapter,
});

Configuring backoff policy​

You can use any of defined backoff policies.

./samples/database-circuit-breaker-backoff-policy.ts
import { DatabaseCircuitBreakerAdapter } from "eridu-tech/circuit-breaker/database-circuit-breaker-adapter";
import { constantBackoff } from "eridu-tech/backoff-policies";
import { circuitBreakerStorageAdapter } from "./circuit-breaker-storage-adapter.js";

const circuitBreakerAdapter = new DatabaseCircuitBreakerAdapter({
adapter: circuitBreakerStorageAdapter,
backoffPolicy: constantBackoff(),
});

Configuring CircuitBreaker policy​

You can use any of defined circuit-breaker policies or create your own.

./samples/database-circuit-breaker-policy.ts
import { DatabaseCircuitBreakerAdapter } from "eridu-tech/circuit-breaker/database-circuit-breaker-adapter";
import { SamplingBreaker } from "eridu-tech/circuit-breaker/policies";
import { circuitBreakerStorageAdapter } from "./circuit-breaker-storage-adapter.js";

const circuitBreakerAdapter = new DatabaseCircuitBreakerAdapter({
adapter: circuitBreakerStorageAdapter,
circuitBreakerPolicy: new SamplingBreaker(),
});

NoOpCircuitBreakerAdapter​

The NoOpCircuitBreakerAdapter is a no-operation implementation, it performs no actions when called:

./samples/no-op-circuit-breaker-adapter.ts
import { NoOpCircuitBreakerAdapter } from "eridu-tech/circuit-breaker/no-op-circuit-breaker-adapter";

const noOpCircuitBreakerAdapter = new NoOpCircuitBreakerAdapter();
info

The NoOpCircuitBreakerAdapter is useful when you want to mock out or disable your CircuitBreakerProvider instance.

KyselyCircuitBreakerStorageAdapter​

To use the KyselyCircuitBreakerStorageAdapter, you'll need to:

  1. Use database provider that has support for transactions.
  2. Install the required dependency: kysely package.
  3. Provide a string serializer (ISerde). We recommend using SuperJsonSerdeAdapter for this purpose.

Setup​

Create the string serializer (ISerde) and a function that creates the TransactionContext by wrapping a Kysely instance in a KyselyTransactionAdapter:

./samples/kysely-circuit-breaker-storage-adapter-setup.ts
import { ExecutionContext } from "eridu-tech/execution-context";
import { AlsExecutionContextAdapter } from "eridu-tech/execution-context/als-execution-context-adapter";
import { contextToken } from "eridu-tech/execution-context/contracts";
import { Serde } from "eridu-tech/serde";
import { SuperJsonSerdeAdapter } from "eridu-tech/serde/super-json-serde-adapter";
import { TransactionContext } from "eridu-tech/transaction-context";
import { KyselyTransactionAdapter } from "eridu-tech/transaction-context/kysely-transaction-adapter";
import type { ITransactionContext } from "eridu-tech/transaction-context/contracts";
import type { Kysely } from "kysely";

export const serde = new Serde(new SuperJsonSerdeAdapter());

const executionContext = new ExecutionContext(new AlsExecutionContextAdapter());

// `KyselyCircuitBreakerStorageAdapter` is transaction aware: it runs every
// circuit-breaker operation through the `current` client of this context,
// which is the transaction-scoped client while a transaction is active and the
// base client otherwise.
export function createTransactionContext(
kysely: Kysely<any>,
): ITransactionContext<Kysely<any>> {
return new TransactionContext<Kysely<any>>({
token: contextToken("kysely"),
adapter: new KyselyTransactionAdapter({
database: kysely,
}),
executionContext,
});
}
info

The transactionContext setting makes the adapter transaction aware. Adapters given the same instance share the same transaction when available.

With Sqlite​

You will need to install better-sqlite3 package:

./samples/kysely-storage-sqlite.ts
import { KyselyCircuitBreakerStorageAdapter } from "eridu-tech/circuit-breaker/kysely-circuit-breaker-storage-adapter";
import Sqlite from "better-sqlite3";
import { Kysely, SqliteDialect } from "kysely";
import {
createTransactionContext,
serde,
} from "./kysely-circuit-breaker-storage-adapter-setup.js";

const database = new Sqlite("DATABASE_NAME.db");
const kysely = new Kysely<any>({
dialect: new SqliteDialect({
database,
}),
});
const transactionContext = createTransactionContext(kysely);
export const kyselyCircuitBreakerStorageAdapter =
new KyselyCircuitBreakerStorageAdapter({
transactionContext,
serde,
});

// You need initialize the adapter once before using it.
// During the initialization the schema will be created
await kyselyCircuitBreakerStorageAdapter.init();

With Postgres​

You will need to install pg package:

./samples/kysely-storage-postgres.ts
import { KyselyCircuitBreakerStorageAdapter } from "eridu-tech/circuit-breaker/kysely-circuit-breaker-storage-adapter";
import { Pool } from "pg";
import { Kysely, PostgresDialect } from "kysely";
import {
createTransactionContext,
serde,
} from "./kysely-circuit-breaker-storage-adapter-setup.js";

const database = new Pool({
database: "DATABASE_NAME",
host: "DATABASE_HOST",
user: "DATABASE_USER",
// DATABASE port
port: 5432,
password: "DATABASE_PASSWORD",
max: 10,
});
const kysely = new Kysely<any>({
dialect: new PostgresDialect({
pool: database,
}),
});
const transactionContext = createTransactionContext(kysely);
const kyselyCircuitBreakerStorageAdapter =
new KyselyCircuitBreakerStorageAdapter({
transactionContext,
serde,
});

// You need initialize the adapter once before using it.
// During the initialization the schema will be created
await kyselyCircuitBreakerStorageAdapter.init();

With Mysql and MariaDB​

You will need to install mysql2 package:

./samples/kysely-storage-mysql.ts
import { KyselyCircuitBreakerStorageAdapter } from "eridu-tech/circuit-breaker/kysely-circuit-breaker-storage-adapter";
import { createPool } from "mysql2";
import { Kysely, MysqlDialect } from "kysely";
import {
createTransactionContext,
serde,
} from "./kysely-circuit-breaker-storage-adapter-setup.js";

const database = createPool({
host: "DATABASE_HOST",
// Database port
port: 3306,
database: "DATABASE_NAME",
user: "DATABASE_USER",
password: "DATABASE_PASSWORD",
connectionLimit: 10,
});
const kysely = new Kysely<any>({
dialect: new MysqlDialect({
pool: database,
}),
});
const transactionContext = createTransactionContext(kysely);
const kyselyCircuitBreakerStorageAdapter =
new KyselyCircuitBreakerStorageAdapter({
transactionContext,
serde,
});

// You need initialize the adapter once before using it.
// During the initialization the schema will be created
await kyselyCircuitBreakerStorageAdapter.init();
info

Works with both MySQL and MariaDB.

With Libsql​

You will need to install @libsql/kysely-libsql package:

./samples/kysely-storage-libsql.ts
import { KyselyCircuitBreakerStorageAdapter } from "eridu-tech/circuit-breaker/kysely-circuit-breaker-storage-adapter";
import { LibsqlDialect } from "@libsql/kysely-libsql";
import { Kysely } from "kysely";
import {
createTransactionContext,
serde,
} from "./kysely-circuit-breaker-storage-adapter-setup.js";

const kysely = new Kysely<any>({
dialect: new LibsqlDialect({
url: "DATABASE_URL",
}),
});
const transactionContext = createTransactionContext(kysely);
const kyselyCircuitBreakerStorageAdapter =
new KyselyCircuitBreakerStorageAdapter({
transactionContext,
serde,
});

// You need initialize the adapter once before using it.
// During the initialization the schema will be created
await kyselyCircuitBreakerStorageAdapter.init();

MemoryCircuitBreakerStorageAdapter​

To use the MemoryCircuitBreakerStorageAdapter you only need to create instance of it:

./samples/memory-circuit-breaker-storage-adapter.ts
import { MemoryCircuitBreakerStorageAdapter } from "eridu-tech/circuit-breaker/memory-circuit-breaker-storage-adapter";

const memoryCircuitBreakerStorageAdapter =
new MemoryCircuitBreakerStorageAdapter();

You can also provide an Map that will be used for storing the data in memory:

./samples/memory-circuit-breaker-storage-with-map.ts
import { MemoryCircuitBreakerStorageAdapter } from "eridu-tech/circuit-breaker/memory-circuit-breaker-storage-adapter";

const map = new Map<any, any>();
const memoryCircuitBreakerStorageAdapter =
new MemoryCircuitBreakerStorageAdapter(map);
info

MemoryCircuitBreakerStorageAdapter lets you test your app without external dependencies like Redis, ideal for local development, unit tests, integration tests and fast E2E test for the backend application.

MongodbCircuitBreakerStorageAdapter​

To use the MongodbCircuitBreakerStorageAdapter, you'll need to:

  1. Use database provider that has support for transactions.
  2. Install the required dependency: mongodb package.
  3. Provide a string serializer (ISerde). We recommend using SuperJsonSerdeAdapter for this purpose.

Setup​

Connect to MongoDB, create the string serializer (ISerde) and the TransactionContext, which wraps the Db instance in a MongodbTransactionAdapter:

./samples/mongodb-circuit-breaker-storage-adapter-setup.ts
import { ExecutionContext } from "eridu-tech/execution-context";
import { AlsExecutionContextAdapter } from "eridu-tech/execution-context/als-execution-context-adapter";
import { contextToken } from "eridu-tech/execution-context/contracts";
import { Serde } from "eridu-tech/serde";
import { SuperJsonSerdeAdapter } from "eridu-tech/serde/super-json-serde-adapter";
import { TransactionContext } from "eridu-tech/transaction-context";
import { MongodbTransactionAdapter } from "eridu-tech/transaction-context/mongodb-transaction-adapter";
import { MongoClient } from "mongodb";
import type { ClientSession, Db } from "mongodb";

export const serde = new Serde(new SuperJsonSerdeAdapter());

const client = await MongoClient.connect("YOUR_MONGODB_CONNECTION_STRING");
const database = client.db("database");

// `MongodbCircuitBreakerStorageAdapter` is transaction aware: it runs every
// circuit-breaker operation through the `current` client of this context.
export const transactionContext = new TransactionContext<Db, ClientSession>({
token: contextToken("mongodb"),
adapter: new MongodbTransactionAdapter({
client,
database,
}),
executionContext: new ExecutionContext(new AlsExecutionContextAdapter()),
});
info

The transactionContext setting makes the adapter transaction aware. Adapters given the same instance share the same transaction when available.

Usage​

Create the adapter:

./samples/mongodb-circuit-breaker-storage-adapter.ts
import { MongodbCircuitBreakerStorageAdapter } from "eridu-tech/circuit-breaker/mongodb-circuit-breaker-storage-adapter";
import {
serde,
transactionContext,
} from "./mongodb-circuit-breaker-storage-adapter-setup.js";

const mongodbCircuitBreakerStorageAdapter =
new MongodbCircuitBreakerStorageAdapter({
transactionContext,
serde,
});

// You need initialize the adapter once before using it.
// During the initialization the indexes will be created
await mongodbCircuitBreakerStorageAdapter.init();

NoOpCircuitBreakerStorageAdapter​

The NoOpCircuitBreakerStorageAdapter is a no-operation implementation, it performs no actions when called:

./samples/no-op-circuit-breaker-storage-adapter.ts
import { NoOpCircuitBreakerStorageAdapter } from "eridu-tech/circuit-breaker/no-op-circuit-breaker-storage-adapter";

const noOpCircuitBreakerStorageAdapter = new NoOpCircuitBreakerStorageAdapter();
info

The NoOpCircuitBreakerStorageAdapter is useful when you want to mock out or disable your DatabaseCircuitBreakerAdapter instance.

Further information​

For further information refer to eridu-tech/circuit-breaker API docs.