Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion src/adapter/basic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,11 @@ export class Adapter<

this.dependencies = this.initializeDependencies(dependencies)

if (this.config.settings.EA_MODE !== 'reader' && this.dependencies.cache.lock) {
if (
this.config.settings.EA_MODE !== 'reader' &&
this.config.settings.CACHE_LOCK_ENABLED &&
this.dependencies.cache.lock
) {
const [lockAcquiredPromise, lockAcquiredResolve, lockAcquiredReject] =
deferredPromise<boolean>()
this.lockAcquiredPromise = lockAcquiredPromise
Expand Down
6 changes: 6 additions & 0 deletions src/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ export const BaseSettingsDefinition = {
default: '/',
sensitive: false,
},
CACHE_LOCK_ENABLED: {
description:
'Flag to enable or disable the cache lock mechanism. When disabled, multiple adapter instances can write to the same cache keys concurrently.',
type: 'boolean',
default: true,
},
CACHE_LOCK_DURATION: {
description: 'Time (in ms) used as a baseline for the acquisition and extension of cache locks',
type: 'number',
Expand Down
71 changes: 71 additions & 0 deletions test/cache/cache-lock.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,75 @@ import { test } from './helper'
// This test needs to use expose to wait for the cache lock promise in the basic EA flow
process.env['EA_PORT'] = '0'

test.serial(
'An adapter with CACHE_LOCK_ENABLED=false should skip lock acquisition even with duplicate names',
async (t) => {
const config = new AdapterConfig(
{},
{
envDefaultOverrides: {
CACHE_TYPE: 'redis',
CACHE_REDIS_PORT: 6000,
CACHE_LOCK_ENABLED: false,
CACHE_LOCK_DEFERRAL_MS: 0,
},
},
)
const adapter = new Adapter({
name: 'TEST',
defaultEndpoint: 'test',
config,
endpoints: [
new AdapterEndpoint({
name: 'nowork',
transport: new NopTransport(),
}),
],
})

const config2 = new AdapterConfig(
{},
{
envDefaultOverrides: {
CACHE_TYPE: 'redis',
CACHE_REDIS_PORT: 6000,
CACHE_LOCK_ENABLED: false,
CACHE_LOCK_DEFERRAL_MS: 0,
},
},
)
const adapter2 = new Adapter({
name: 'TEST',
defaultEndpoint: 'test',
config: config2,
endpoints: [
new AdapterEndpoint({
name: 'nowork',
transport: new NopTransport(),
}),
],
})

const redisClient = new RedisMock() as unknown as Redis
const cache = new RedisCache(redisClient, 10000)
const dependencies: Partial<AdapterDependencies> = {
cache,
redisClient,
}

try {
await expose(adapter, dependencies)
await expose(adapter2, dependencies)

t.is(adapter.lockAcquiredPromise, undefined)
t.is(adapter2.lockAcquiredPromise, undefined)
t.pass()
} catch (error) {
t.fail(`No error should have been thrown with CACHE_LOCK_ENABLED=false: ${error}`)
}
},
)

test.serial(
'An adapter with a duplicate name and no cache prefix should fail to acquire a lock',
async (t) => {
Expand All @@ -19,6 +88,7 @@ test.serial(
envDefaultOverrides: {
CACHE_TYPE: 'redis',
CACHE_REDIS_PORT: 6000,
CACHE_PREFIX: 'PREFIX',
CACHE_LOCK_DURATION: 2000,
CACHE_LOCK_RETRIES: 2,
CACHE_LOCK_DEFERRAL_MS: 0,
Expand All @@ -43,6 +113,7 @@ test.serial(
envDefaultOverrides: {
CACHE_TYPE: 'redis',
CACHE_REDIS_PORT: 6000,
CACHE_PREFIX: 'PREFIX',
CACHE_LOCK_DURATION: 2000,
CACHE_LOCK_RETRIES: 2,
CACHE_LOCK_DEFERRAL_MS: 0,
Expand Down
Loading