chore: add sync backoff mechanism checks (#2786)

This commit is contained in:
Karol Sójko
2024-01-23 09:04:55 +01:00
committed by GitHub
parent 2757884d10
commit ba236a2f2b
7 changed files with 115 additions and 1 deletions

View 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)
})
})

View 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())
}
}

View File

@@ -0,0 +1,6 @@
import { AnyItemInterface } from '@standardnotes/models'
export interface SyncBackoffServiceInterface {
isItemInBackoff(item: AnyItemInterface): boolean
backoffItem(item: AnyItemInterface): void
}