Skip to main content

DI Integration

The sharedLockFactoryResolverDiFactory function creates an ISharedLockFactoryResolver whose underlying resolver is resolved from a DI container.

The returned proxy implements both ISharedLockFactoryResolver and ISharedLockFactory:

  • use(adapterName?) selects an adapter on the resolved SharedLockFactoryResolver.
  • create(key, settings) creates a shared lock through the resolver's default adapter.

The proxy is wired to the container during container.init(). Create it before calling init(); calling use() or create() before the container is initialized throws an error.

Initial configuration​

Set up the memory and Redis shared-lock adapters, create the container, then register the SharedLockFactoryResolver and wrap it with sharedLockFactoryResolverDiFactory:

1. Set up the memory shared-lock adapter​

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

export const memorySharedLockAdapter = new MemorySharedLockAdapter();

2. Set up the Redis shared-lock adapter​

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

export const redisSharedLockAdapter = new RedisSharedLockAdapter(
new Redis("YOUR_REDIS_CONNECTION_STRING"),
);

3. Create the dependency injection container​

./samples/container.ts
import { Container } from "eridu-tech/di";
import { ExecutionContext } from "eridu-tech/execution-context";
import { AlsExecutionContextAdapter } from "eridu-tech/execution-context/als-execution-context-adapter";

export const executionContext = new ExecutionContext(
new AlsExecutionContextAdapter(),
);
export const container = new Container({ executionContext });

4. Register and initialize the shared-lock factory resolver​

./samples/shared-lock-factory-resolver-di-factory.ts
import { SharedLockFactoryResolver } from "eridu-tech/shared-lock";
import { ProxySharedLockFactoryResolver } from "eridu-tech/shared-lock/di";
import { container } from "./container.js";
import { memorySharedLockAdapter } from "./memory-shared-lock-adapter.js";
import { redisSharedLockAdapter } from "./redis-shared-lock-adapter.js";

type Adapters = "memory" | "redis";

const sharedLockFactoryResolver = new SharedLockFactoryResolver<Adapters>({
adapters: {
memory: memorySharedLockAdapter,
redis: redisSharedLockAdapter,
},
defaultAdapter: "memory",
});

await sharedLockFactoryResolver.init();

container.registerValue({
token: SharedLockFactoryResolver,
value: sharedLockFactoryResolver,
});

// Create the proxy before container.init()
export const sharedLockFactory = new ProxySharedLockFactoryResolver<Adapters>({
container,
resolverToken: SharedLockFactoryResolver,
});

await container.init();

Usage​

1. Using the default adapter​

./samples/shared-lock-factory-resolver-di-factory-default-adapter.ts
import { sharedLockFactory } from "./shared-lock-factory-resolver-di-factory.js";

// Uses the adapter configured as the default (memory)
await sharedLockFactory
.create("shared-resource", {
limit: 4,
})
.runWriterOrFail(async () => {
// code to run
});

2. Specifying an adapter explicitly​

./samples/shared-lock-factory-resolver-di-factory-specific-adapter.ts
import { sharedLockFactory } from "./shared-lock-factory-resolver-di-factory.js";

// Uses the Redis adapter
await sharedLockFactory
.use("redis")
.create("shared-resource", {
limit: 4,
})
.runWriterOrFail(async () => {
// code to run
});

Using it with the middlewares​

Because the proxy implements ISharedLockFactoryResolver, it can be passed straight to the shared-lock middleware factories:

./samples/shared-lock-factory-resolver-di-factory-with-middleware.ts
import { use } from "eridu-tech/middleware";
import {
SHARED_LOCK_WHEN,
withSharedLockFactory,
} from "eridu-tech/shared-lock/middlewares";
import { sharedLockFactory } from "./shared-lock-factory-resolver-di-factory.js";

const withSharedLock = withSharedLockFactory(sharedLockFactory);

const readData = async (key: string): Promise<unknown> => {
// Safe to run concurrently with other readers
return { data: "..." };
};

const safeRead = use(
readData,
withSharedLock.use("redis")({
key: ([resourceKey]) => `data:${resourceKey}`,
when: SHARED_LOCK_WHEN.READER,
limit: 10,
}),
);

await safeRead("config");

Further information​

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