chore: add sync backoff mechanism checks (#2786)
This commit is contained in:
55
packages/services/src/Domain/Sync/SyncBackoffService.spec.ts
Normal file
55
packages/services/src/Domain/Sync/SyncBackoffService.spec.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
import { AnyItemInterface } from '@standardnotes/models'
|
||||
import { SyncBackoffService } from './SyncBackoffService'
|
||||
|
||||
describe('SyncBackoffService', () => {
|
||||
const createService = () => new SyncBackoffService()
|
||||
|
||||
it('should not be in backoff if no backoff was set', () => {
|
||||
const service = createService()
|
||||
|
||||
expect(service.isItemInBackoff({ uuid: '123' } as jest.Mocked<AnyItemInterface>)).toBe(false)
|
||||
})
|
||||
|
||||
it('should be in backoff if backoff was set', () => {
|
||||
const service = createService()
|
||||
|
||||
service.backoffItem({ uuid: '123' } as jest.Mocked<AnyItemInterface>)
|
||||
|
||||
expect(service.isItemInBackoff({ uuid: '123' } as jest.Mocked<AnyItemInterface>)).toBe(true)
|
||||
})
|
||||
|
||||
it('should not be in backoff if backoff expired', () => {
|
||||
const service = createService()
|
||||
|
||||
jest.spyOn(Date, 'now').mockReturnValueOnce(1_000_000)
|
||||
|
||||
service.backoffItem({ uuid: '123' } as jest.Mocked<AnyItemInterface>)
|
||||
|
||||
jest.spyOn(Date, 'now').mockReturnValueOnce(2_000_000)
|
||||
|
||||
expect(service.isItemInBackoff({ uuid: '123' } as jest.Mocked<AnyItemInterface>)).toBe(false)
|
||||
})
|
||||
|
||||
it('should double backoff penalty on each backoff', () => {
|
||||
const service = createService()
|
||||
|
||||
jest.spyOn(Date, 'now').mockReturnValueOnce(1_000_000)
|
||||
|
||||
service.backoffItem({ uuid: '123' } as jest.Mocked<AnyItemInterface>)
|
||||
|
||||
jest.spyOn(Date, 'now').mockReturnValueOnce(1_000_000)
|
||||
expect(service.isItemInBackoff({ uuid: '123' } as jest.Mocked<AnyItemInterface>)).toBe(true)
|
||||
|
||||
jest.spyOn(Date, 'now').mockReturnValueOnce(1_000_000)
|
||||
service.backoffItem({ uuid: '123' } as jest.Mocked<AnyItemInterface>)
|
||||
|
||||
jest.spyOn(Date, 'now').mockReturnValueOnce(1_001_000)
|
||||
expect(service.isItemInBackoff({ uuid: '123' } as jest.Mocked<AnyItemInterface>)).toBe(true)
|
||||
|
||||
jest.spyOn(Date, 'now').mockReturnValueOnce(1_000_000)
|
||||
service.backoffItem({ uuid: '123' } as jest.Mocked<AnyItemInterface>)
|
||||
|
||||
jest.spyOn(Date, 'now').mockReturnValueOnce(1_003_000)
|
||||
expect(service.isItemInBackoff({ uuid: '123' } as jest.Mocked<AnyItemInterface>)).toBe(true)
|
||||
})
|
||||
})
|
||||
37
packages/services/src/Domain/Sync/SyncBackoffService.ts
Normal file
37
packages/services/src/Domain/Sync/SyncBackoffService.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { AnyItemInterface } from '@standardnotes/models'
|
||||
import { SyncBackoffServiceInterface } from './SyncBackoffServiceInterface'
|
||||
|
||||
export class SyncBackoffService implements SyncBackoffServiceInterface {
|
||||
private backoffPenalties: Map<string, number>
|
||||
private backoffStartTimestamps: Map<string, number>
|
||||
|
||||
constructor() {
|
||||
this.backoffPenalties = new Map<string, number>()
|
||||
this.backoffStartTimestamps = new Map<string, number>()
|
||||
}
|
||||
|
||||
isItemInBackoff(item: AnyItemInterface): boolean {
|
||||
const backoffStartingTimestamp = this.backoffStartTimestamps.get(item.uuid)
|
||||
if (!backoffStartingTimestamp) {
|
||||
return false
|
||||
}
|
||||
|
||||
const backoffPenalty = this.backoffPenalties.get(item.uuid)
|
||||
if (!backoffPenalty) {
|
||||
return false
|
||||
}
|
||||
|
||||
const backoffEndTimestamp = backoffStartingTimestamp + backoffPenalty
|
||||
|
||||
return backoffEndTimestamp > Date.now()
|
||||
}
|
||||
|
||||
backoffItem(item: AnyItemInterface): void {
|
||||
const backoffPenalty = this.backoffPenalties.get(item.uuid) || 0
|
||||
|
||||
const newBackoffPenalty = backoffPenalty === 0 ? 1_000 : backoffPenalty * 2
|
||||
|
||||
this.backoffPenalties.set(item.uuid, newBackoffPenalty)
|
||||
this.backoffStartTimestamps.set(item.uuid, Date.now())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
import { AnyItemInterface } from '@standardnotes/models'
|
||||
|
||||
export interface SyncBackoffServiceInterface {
|
||||
isItemInBackoff(item: AnyItemInterface): boolean
|
||||
backoffItem(item: AnyItemInterface): void
|
||||
}
|
||||
Reference in New Issue
Block a user