-
Notifications
You must be signed in to change notification settings - Fork 39
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: duplicate bids publication (#1747)
* chore: update development dump * fix: fetch current bid number each time on creation * fix: run publishBids with lock * fix: change withLock signature and tests to accept job context * chore: address pr comments * chore: update snapshot testnet url * chore: publish bids every 5 minutes
- Loading branch information
Showing
9 changed files
with
117 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
import JobContext from 'decentraland-gatsby/dist/entities/Job/context' | ||
|
||
import { JOB_LOCKS, isLockAcquired, withLock } from './jobLocks' | ||
|
||
describe('Job Locking Mechanism', () => { | ||
const exampleContext: JobContext = new JobContext( | ||
'id', | ||
'handler', | ||
{}, | ||
async () => {}, | ||
async () => {} | ||
) | ||
|
||
const immediateJob = jest.fn().mockResolvedValue(0) | ||
|
||
const delayedJob = jest | ||
.fn() | ||
.mockImplementation( | ||
() => new Promise((resolve, reject) => setTimeout(() => reject(new Error('Simulated job error')), 100)) | ||
) | ||
|
||
beforeEach(() => { | ||
JOB_LOCKS.clear() | ||
jest.clearAllMocks() | ||
}) | ||
|
||
it('should acquire and release lock for a job that completes successfully', async () => { | ||
const jobName = 'immediateJob' | ||
const lockedJob = withLock(jobName, immediateJob) | ||
|
||
expect(isLockAcquired(jobName)).toBe(false) | ||
await lockedJob(exampleContext) | ||
|
||
expect(immediateJob).toHaveBeenCalledTimes(1) | ||
expect(isLockAcquired(jobName)).toBe(false) | ||
}) | ||
|
||
it('should acquire and release lock for a job that fails', async () => { | ||
const jobName = 'delayedJob' | ||
const lockedJob = withLock(jobName, delayedJob) | ||
|
||
try { | ||
await lockedJob(exampleContext) | ||
} catch (error) { | ||
expect(delayedJob).toHaveBeenCalledTimes(1) | ||
expect(isLockAcquired(jobName)).toBe(false) // Lock should be released even on error | ||
expect(error).toBeDefined() // Ensure error is thrown | ||
} | ||
}) | ||
|
||
it('should not execute job if it is already running', async () => { | ||
const jobName = 'concurrentJob' | ||
const firstJob = withLock(jobName, delayedJob) | ||
const secondJob = withLock(jobName, immediateJob) | ||
|
||
const firstPromise = firstJob(exampleContext) | ||
const secondPromise = secondJob(exampleContext) | ||
try { | ||
await Promise.all([firstPromise, secondPromise]) | ||
} catch (error) { | ||
expect((error as Error).message).toBe('Simulated job error') | ||
} | ||
|
||
expect(delayedJob).toHaveBeenCalledTimes(1) | ||
expect(immediateJob).not.toHaveBeenCalled() | ||
|
||
// Try again after lock is released | ||
await secondJob(exampleContext) | ||
expect(immediateJob).toHaveBeenCalledTimes(1) // Second job should execute now | ||
|
||
expect(isLockAcquired(jobName)).toBe(false) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import JobContext from 'decentraland-gatsby/dist/entities/Job/context' | ||
|
||
type JobFunction = (context: JobContext) => Promise<void> | ||
|
||
export const JOB_LOCKS = new Map<string, boolean>() | ||
|
||
export const isLockAcquired = (jobName: string): boolean => { | ||
return JOB_LOCKS.has(jobName) | ||
} | ||
|
||
const acquireLock = (jobName: string): void => { | ||
JOB_LOCKS.set(jobName, true) | ||
} | ||
|
||
const releaseLock = (jobName: string): void => { | ||
JOB_LOCKS.delete(jobName) | ||
} | ||
|
||
export const withLock = (jobName: string, jobFunction: JobFunction) => async (context: JobContext) => { | ||
if (isLockAcquired(jobName)) { | ||
console.log(`${jobName} is already running.`) | ||
return | ||
} | ||
acquireLock(jobName) | ||
try { | ||
await jobFunction(context) | ||
} finally { | ||
releaseLock(jobName) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters