mirror of
https://github.com/elastic/kibana.git
synced 2025-06-27 10:40:07 -04:00
[LockManager] Update token and metadata when an expired lock is re-acquired (#220476)
Related: https://github.com/elastic/kibana/pull/216397 This fixes a bug in the Lock Manager where an expired lock can be acquired, but the token and metadata is not updated. This means that the lock cannot be released. Instead it is automatically released when the TTL expires.
This commit is contained in:
parent
9fc42af400
commit
74e876d12d
2 changed files with 38 additions and 12 deletions
|
@ -87,6 +87,8 @@ export class LockManager {
|
||||||
def instantNow = Instant.ofEpochMilli(now);
|
def instantNow = Instant.ofEpochMilli(now);
|
||||||
ctx._source.createdAt = instantNow.toString();
|
ctx._source.createdAt = instantNow.toString();
|
||||||
ctx._source.expiresAt = instantNow.plusMillis(params.ttl).toString();
|
ctx._source.expiresAt = instantNow.plusMillis(params.ttl).toString();
|
||||||
|
ctx._source.metadata = params.metadata;
|
||||||
|
ctx._source.token = params.token;
|
||||||
} else {
|
} else {
|
||||||
ctx.op = 'noop';
|
ctx.op = 'noop';
|
||||||
}
|
}
|
||||||
|
@ -94,13 +96,11 @@ export class LockManager {
|
||||||
params: {
|
params: {
|
||||||
ttl,
|
ttl,
|
||||||
token: this.token,
|
token: this.token,
|
||||||
|
metadata,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
upsert: {
|
upsert: {},
|
||||||
metadata,
|
|
||||||
token: this.token,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
retryOnTimeout: true,
|
retryOnTimeout: true,
|
||||||
|
@ -189,7 +189,7 @@ export class LockManager {
|
||||||
this.logger.debug(`Lock "${this.lockId}" released with token ${this.token}.`);
|
this.logger.debug(`Lock "${this.lockId}" released with token ${this.token}.`);
|
||||||
return true;
|
return true;
|
||||||
case 'noop':
|
case 'noop':
|
||||||
this.logger.debug(
|
this.logger.warn(
|
||||||
`Lock "${this.lockId}" with token = ${this.token} could not be released. Token does not match.`
|
`Lock "${this.lockId}" with token = ${this.token} could not be released. Token does not match.`
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -236,15 +236,41 @@ export default function ApiTest({ getService }: DeploymentAgnosticFtrProviderCon
|
||||||
expect(lock?.metadata).to.eql({ attempt: 'one' });
|
expect(lock?.metadata).to.eql({ attempt: 'one' });
|
||||||
});
|
});
|
||||||
|
|
||||||
it('allows re-acquisition after expiration', async () => {
|
describe('when a lock by "manager1" expires, and is attempted re-acquired by "manager2"', () => {
|
||||||
// Acquire with a very short TTL.
|
let expiredLock: LockDocument | undefined;
|
||||||
const acquired = await manager1.acquire({ ttl: 500, metadata: { attempt: 'one' } });
|
let reacquireResult: boolean;
|
||||||
expect(acquired).to.be(true);
|
beforeEach(async () => {
|
||||||
|
// Acquire with a very short TTL.
|
||||||
|
const acquired = await manager1.acquire({ ttl: 500, metadata: { attempt: 'one' } });
|
||||||
|
expect(acquired).to.be(true);
|
||||||
|
await sleep(1000); // wait for lock to expire
|
||||||
|
expiredLock = await getLockById(es, LOCK_ID);
|
||||||
|
reacquireResult = await manager2.acquire({ metadata: { attempt: 'two' } });
|
||||||
|
});
|
||||||
|
|
||||||
await sleep(1000); // wait for lock to expire
|
it('can be re-acquired', async () => {
|
||||||
|
expect(reacquireResult).to.be(true);
|
||||||
|
});
|
||||||
|
|
||||||
const reacquired = await manager2.acquire({ metadata: { attempt: 'two' } });
|
it('updates the token when re-acquired', async () => {
|
||||||
expect(reacquired).to.be(true);
|
const reacquiredLock = await getLockById(es, LOCK_ID);
|
||||||
|
expect(expiredLock?.token).not.to.be(reacquiredLock?.token);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('updates the metadata when re-acquired', async () => {
|
||||||
|
const reacquiredLock = await getLockById(es, LOCK_ID);
|
||||||
|
expect(reacquiredLock?.metadata).to.eql({ attempt: 'two' });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('cannot be released by "manager1"', async () => {
|
||||||
|
const res = await manager1.release();
|
||||||
|
expect(res).to.be(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can be released by "manager2"', async () => {
|
||||||
|
const res = await manager2.release();
|
||||||
|
expect(res).to.be(true);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue