Skip to main content

Configuring SharedLock adapters

MemorySharedLockAdapter​

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

./samples/memory-shared-lock-adapter.ts
import { MemorySharedLockAdapter } from "eridu-tech/shared-lock/memory-shared-lock-adapter";

export const memorySharedLockAdapter = new MemorySharedLockAdapter();

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

./samples/memory-shared-lock-adapter-with-map.ts
import { MemorySharedLockAdapter } from "eridu-tech/shared-lock/memory-shared-lock-adapter";

const map = new Map<any, any>();
const memorySharedLockAdapter = new MemorySharedLockAdapter(map);
info

MemorySharedLockAdapter 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.

danger

Note the MemorySharedLockAdapter is limited to single process usage and cannot be shared across multiple servers or processes.

Settings​

To clean up expired shared-lock keys, call removeAllExpired at a regular interval (for example, using a cron job):

./samples/memory-shared-lock-remove-all-expired.ts
import { memorySharedLockAdapter } from "./memory-shared-lock-adapter.js";

// Remove all expired shared-lock keys manually.
await memorySharedLockAdapter.removeAllExpired();

To remove the shared-lock map and all stored shared-lock data, use deInit method:

./samples/memory-shared-lock-adapter-deinit.ts
import { memorySharedLockAdapter } from "./memory-shared-lock-adapter.js";

await memorySharedLockAdapter.deInit();

MongodbSharedLockAdapter​

To use the MongodbSharedLockAdapter, you'll need to:

  1. Install the required dependency: mongodb package.

Setup​

Connect to MongoDB:

./samples/mongodb-shared-lock-adapter-setup.ts
import { MongoClient } from "mongodb";

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

The database setting also accepts a TransactionContext, which makes the adapter transaction aware. Adapters given the same instance share the same transaction when available.

Usage​

Create the adapter:

./samples/mongodb-shared-lock-adapter.ts
import { MongodbSharedLockAdapter } from "eridu-tech/shared-lock/mongodb-shared-lock-adapter";
import { database } from "./mongodb-shared-lock-adapter-setup.js";

export const mongodbSharedLockAdapter = new MongodbSharedLockAdapter({
database,
});

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

You can change the collection name:

./samples/mongodb-shared-lock-collection-name.ts
import { MongodbSharedLockAdapter } from "eridu-tech/shared-lock/mongodb-shared-lock-adapter";
import { database } from "./mongodb-shared-lock-adapter-setup.js";

const mongodbSharedLockAdapter = new MongodbSharedLockAdapter({
database,
// By default "shared-lock" is used as collection name
collectionName: "my-shared-lock",
});

await mongodbSharedLockAdapter.init();

You can change the collection settings:

./samples/mongodb-shared-lock-collection-settings.ts
import { MongodbSharedLockAdapter } from "eridu-tech/shared-lock/mongodb-shared-lock-adapter";
import { database } from "./mongodb-shared-lock-adapter-setup.js";

const mongodbSharedLockAdapter = new MongodbSharedLockAdapter({
database,
// You configure additional collection settings
collectionSettings: {},
});

await mongodbSharedLockAdapter.init();
info

To remove the shared-lock collection and all stored shared-lock data, use deInit method:

./samples/mongodb-shared-lock-adapter-deinit.ts
import { mongodbSharedLockAdapter } from "./mongodb-shared-lock-adapter.js";

await mongodbSharedLockAdapter.deInit();
danger

Note in order to use MongodbSharedLockAdapter correctly, ensure you use a single, consistent database across all server instances or processes.

RedisSharedLockAdapter​

To use the RedisSharedLockAdapter, you'll need to:

  1. Install the required dependency: ioredis package.

Setup​

Connect to Redis:

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

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

Usage​

Create the adapter:

./samples/redis-shared-lock-adapter.ts
import { RedisSharedLockAdapter } from "eridu-tech/shared-lock/redis-shared-lock-adapter";
import { database } from "./redis-shared-lock-adapter-setup.js";

const redisSharedLockAdapter = new RedisSharedLockAdapter(database);
danger

Note in order to use RedisSharedLockAdapter correctly, ensure you use a single, consistent database across all server instances or processes.

KyselySharedLockAdapter​

To use the KyselySharedLockAdapter, you'll need to:

  1. Use database provider that has support for transactions.
  2. Install the required dependency: kysely package.

Setup​

Create a function that creates the TransactionContext by wrapping a Kysely instance in a KyselyTransactionAdapter:

./samples/kysely-shared-lock-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 { 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";

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

// `KyselySharedLockAdapter` is transaction aware: it runs every shared-lock
// 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-shared-lock-sqlite.ts
import { KyselySharedLockAdapter } from "eridu-tech/shared-lock/kysely-shared-lock-adapter";
import Sqlite from "better-sqlite3";
import { Kysely, SqliteDialect } from "kysely";
import { createTransactionContext } from "./kysely-shared-lock-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 kyselySharedLockAdapter = new KyselySharedLockAdapter({
transactionContext,
});

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

Note using KyselySharedLockAdapter with sqlite is limited to single server usage and cannot be shared across multiple servers but it can be shared between different processes. To use it correctly, ensure all process instances access the same persisted database.

With Postgres​

You will need to install pg package:

./samples/kysely-shared-lock-postgres.ts
import { KyselySharedLockAdapter } from "eridu-tech/shared-lock/kysely-shared-lock-adapter";
import { Pool } from "pg";
import { Kysely, PostgresDialect } from "kysely";
import { createTransactionContext } from "./kysely-shared-lock-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 kyselySharedLockAdapter = new KyselySharedLockAdapter({
transactionContext,
});

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

Note in order to use KyselySharedLockAdapter with postgres correctly, ensure you use a single, consistent database across all server instances. This means you can't use replication.

With Mysql​

You will need to install mysql2 package:

./samples/kysely-shared-lock-mysql.ts
import { KyselySharedLockAdapter } from "eridu-tech/shared-lock/kysely-shared-lock-adapter";
import { createPool } from "mysql2";
import { Kysely, MysqlDialect } from "kysely";
import { createTransactionContext } from "./kysely-shared-lock-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 kyselySharedLockAdapter = new KyselySharedLockAdapter({
transactionContext,
});

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

Note in order to use KyselySharedLockAdapter with mysql correctly, ensure you use a single, consistent database across all server instances. This means you can't use replication.

With Libsql​

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

./samples/kysely-shared-lock-libsql.ts
import { KyselySharedLockAdapter } from "eridu-tech/shared-lock/kysely-shared-lock-adapter";
import { LibsqlDialect } from "@libsql/kysely-libsql";
import { Kysely } from "kysely";
import { createTransactionContext } from "./kysely-shared-lock-adapter-setup.js";

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

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

Note in order to use KyselySharedLockAdapter with libsql correctly, ensure you use a single, consistent database across all server instances. This means you can't use libsql embedded replicas.

Settings​

To clean up expired shared-lock keys, call removeAllExpired at a regular interval (for example, using a cron job):

./samples/kysely-shared-lock-remove-all-expired.ts
import { kyselySharedLockAdapter } from "./kysely-shared-lock-sqlite.js";

// Remove all expired shared-lock keys manually.
await kyselySharedLockAdapter.removeAllExpired();

To remove the shared-lock table and all stored shared-lock data, use deInit method:

./samples/kysely-shared-lock-adapter-deinit.ts
import { kyselySharedLockAdapter } from "./kysely-shared-lock-sqlite.js";

await kyselySharedLockAdapter.deInit();

NoOpSharedLockAdapter​

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

./samples/no-op-shared-lock-adapter.ts
import { NoOpSharedLockAdapter } from "eridu-tech/shared-lock/no-op-shared-lock-adapter";

const noOpSharedLockAdapter = new NoOpSharedLockAdapter();
info

The NoOpSharedLockAdapter is useful when you want to mock out or disable your SharedLockFactory instance.

Further information​

For further information refer to eridu-tech/shared-lock API docs.